无法在 'DOMWindow' 上执行 'postMessage':target/origin 不匹配 http 与 https

Failed to execute 'postMessage' on 'DOMWindow': target/origin mismatch http vs https

我很抱歉我的问题让我很困惑。我真的很为难,因为这导致我的生产站点出现问题。

我的网站上有一个 javascript 播放器,它播放可以托管在 youtube、soundcloud 或 vimeo 上的歌曲列表。昨天我注意到这个错误,通常在您尝试使用播放器按钮通过 "skipping" 加载新歌曲时出现。这个错误是最近一两天才开始的。我在 youtube api 发行说明中没有看到任何新内容,并且此错误发生在使用 Chrome、Firefox 和 Safari 时,因此它很可能与浏览器的更改无关。不过,我正在使用的东西发生了变化,因为我已经 18 天没有推送新代码了。

示例播放列表如下:http://www.muusical.com/playlists/programming-music

我想我已经隔离了重现错误的方法,步骤如下:

  1. 播放 YouTube 托管的歌曲。
  2. 跳到列表中的任何其他歌曲(无论是按跳过按钮还是直接按歌曲行项目上的播放按钮)。

*请注意,如果播放列表中的第一首歌曲是 youtube 歌曲,即使不播放最初加载的 youtube 歌曲而直接跳到另一首歌曲也会产生错误。

基本上,错误似乎是在您加载 and/or 播放了一首 YouTube 歌曲并试图跳到另一首歌曲时发生的。

如果您发现此行为有异常,请告诉我。

我在控制台中看到这个错误:

Failed to execute 'postMessage' on 'DOMWindow': The target origin provided ('https://www.muusical.com') does not match the recipient window's origin ('http://www.muusical.com').

我使用 youtube 加载播放器 javascript api:

new YT.Player('playlist-player', {
      playerVars: { 'autoplay': 1, 'fs': 0 },
      videoId: "gJ6APKIjFQY",
      events: {
        'onReady': @initPlayerControls,
        'onStateChange': @onPlayerStateChange
      }
    })

生成此 iframe 的对象:

<iframe id="playlist-player" frameborder="0" allowfullscreen="1" title="YouTube video player" width="640" height="360" src="https://www.youtube.com/embed/gJ6APKIjFQY?autoplay=1&amp;enablejsapi=1&amp;origin=http%3A%2F%2Fwww.muusical.com"></iframe>

从上面的 youtube 歌曲中点击跳过后,这是我在 iframe 中看到的加载内容:

<iframe id="playlist-player" frameborder="0" allowfullscreen="1" title="YouTube video player" width="640" height="360" src=""></iframe>

我支持 youtube、soundcloud 和 vimeo 歌曲。似乎一旦加载了 YouTube 歌曲,"origin" 就会从 http 更改为 https。我认为没有必要包括其他主机的嵌入方法,因为即使整个播放列表只是 youtube 也会发生此错误,并且它不会出现在仅包含来自 soundcloud 和 vimeo 的歌曲的播放列表中。

此外,这就是我加载 youtube 的方式 javascript:

// Load the IFrame Player API code asynchronously.
  var tag = document.createElement('script');
  tag.src = "https://www.youtube.com/player_api";
  var firstScriptTag = document.getElementsByTagName('script')[0];
  firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

如果您需要我澄清任何事情,请告诉我,在此先感谢您的查看。

我读过一些关于这个的文章,一些 SO 帖子在这里和那里还有这个 link:https://code.google.com/p/gdata-issues/issues/detail?id=5788

我正要对你的问题添加评论,说我对此感到疯狂......但是当我开始描述我的设置时,我找到了避免这个问题的方法^^。

我从一个空的 div 元素开始,然后使用 Youtube Iframe API 将其变成具有所有必要选项的 iframe

我有多个像这个这样的 div,并且通常使用相同的 JS 变量来存储所有这些播放器,但一次一个(一个替换另一个,依此类推...... - 它可能会更好,我知道)。

为了解决这个问题,我想用 摧毁 玩家 youtubePlayer.destroy(); 然后再从另一个元素构建新的玩家。我的 Chrome 控制台中不再出现 JS 错误:).

希望对你有帮助,我能读到的关于 http 和 https 的所有文献都不适用于我的情况,因为我没有自己设置 iframe URL,而我的网站恰好是 https ...

我确实在 HTML 中恢复了异步调用而不是静态 script 标记,但我认为这没有必要。

EDIT:这个错误消息实际上非常具有误导性,它只是含糊地表示:你没有以正确的方式使用 youtube API:)

@sodawillow 的回答部分正确,但我想提供解决方案的详细信息以及导致我的代码停止调用 .destroy() 方法以删除 youtube 播放器的原因。

我的网站有一个播放器,可以交换来自不同网站的歌曲,其中之一是 Youtube。根据播放器的类型,可以使用不同的方法来移除播放器。我的代码检查是否存在 youtube 播放器,如果通过检查,则它使用只有 youtube 播放器才有的 .destroy() 方法。问题是 YouTube 更改了播放器对象上某些静态变量的名称。例如,如果我通过以下方式创建了一个播放器:

var player = new YT.Player('playlist-player', {
      playerVars: { 'autoplay': 1, 'fs': 0 },
      videoId: "gJ6APKIjFQY",
      events: {
      }
    })

然后会有一个变量 player.L 保存字符串 "player"。因此,为了检查当前播放器是否是 YouTube 播放器并将其删除,我这样做了:

if (player.L == "player") {
  player.destroy();
} else {
//handle the removal of the Soundcloud or Vimeo player.
}

最近 Youtube 将字符串 "player" 的位置更改为现在位于 player.M。我可以更改上面的代码以检查 player.M 而不是 player.L,这会起作用,但为了避免将来出现此问题,我改为实施:

if (player.destroy) {
  player.destroy();
} else {
//handle the removal of the Soundcloud or Vimeo player.
}

只要 Youtube 不删除 .destroy() 方法,这不会导致任何问题。

所以综上所述,问题正如@sodawillow 猜测的那样,我没有使用 .destroy() 方法删除 Youtube 播放器。原因是 Youtube 对其 api 进行了一些未经宣布的更改,更改了一些静态变量的位置。

我的解决方案是将所有 Youtube 播放器逻辑写在单独的页面中(尽可能空白),并在 IFRAME 标记中引用该页面。

<iframe src="/youtube_frame/?data=SOME_DATA -%>" height="400px" width="100%" frameborder="0" border="0" scrolling="no"></iframe>

那么,你的youtube_frame.html会是这样的:

<!DOCTYPE html>
<html>
  <body>
    <!-- 1. The <iframe> (and video player) will replace this <div> tag. -->
    <div id="player"></div>

    <script>
      // 2. This code loads the IFrame Player API code asynchronously.
      var tag = document.createElement('script');

      tag.src = "https://www.youtube.com/iframe_api";
      var firstScriptTag = document.getElementsByTagName('script')[0];
      firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

      // 3. This function creates an <iframe> (and YouTube player)
      //    after the API code downloads.
      var player;
      function onYouTubeIframeAPIReady() {
        player = new YT.Player('player', {
          height: '390',
          width: '640',
          videoId: 'M7lc1UVf-VE',
          events: {
            'onReady': onPlayerReady,
            'onStateChange': onPlayerStateChange
          }
        });
      }

      // 4. The API will call this function when the video player is ready.
      function onPlayerReady(event) {
        // event.target.playVideo();
      }

      // 5. The API calls this function when the player's state changes.
      //    The function indicates that when playing a video (state=1),
      //    the player should play for six seconds and then stop.
      var done = false;
      function onPlayerStateChange(event) {
        console.log("OnplayerStateChange");
        if (event.data == YT.PlayerState.PLAYING && !done) {
          console.log("OnplayerStateChange - If statement");
          setTimeout(stopVideo, 6000);
          done = true;
        }
      }
      function stopVideo() {
        player.stopVideo();
      }
    </script>
  </body>
</html>

(作为旁注:我的上下文是 Prototype.js 干扰了事件 'OnStateChange',我们无法消除这种依赖性。 使用 jsfiddle 对重现问题没有用,因为它几乎没有依赖项。 我的应用程序内置于 Rails,并使用此插件显示视频播放列表:https://github.com/Giorgio003/Youtube-TV/)

此错误属于 Google Youtube API。

在“https://www.youtube.com/iframe_api”内:

if (!window['YT']) {
    var YT = {loading: 0, loaded: 0};
}
if (!window['YTConfig']) {
    var YTConfig = {'host': 'http://www.youtube.com'};
}

他们使用 http 而不是 https。

我们需要覆盖 'host' 选项和 'widget_referrer' 与 'origin' 相同。

player = new YT.Player('player', {
          host: 'https://www.youtube.com',
          height: '390',
          width: '640',
          videoId: 'M7lc1UVf-VE'
...
          origin: "https://www.enziin.com",
          widget_referrer: "https://www.enziin.com"
}

祝你好运。