无法执行' postMessage'在' DOMWindow':目标/来源不匹配http vs https

时间:2015-01-11 00:13:30

标签: target postmessage ytplayer

我道歉,因为我对我的问题非常困惑。我真的处于绑定状态,因为这会导致我的生产网站出现问题。

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

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

我认为我已经隔离了重现错误的方法,以下是步骤:

  1. 播放youtube托管歌曲。
  2. 跳至列表中的任何其他歌曲(无论是按下跳过按钮还是直接按歌曲的行项目上的播放按钮)。
  3. *请注意,如果播放列表中的第一首歌是youtube歌曲,即使不播放最初加载的youtube歌曲,只是跳到另一首歌曲也会产生错误。

    基本上,一旦你加载和/或播放了一首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歌曲加载了&#34;起源&#34;从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);
    

    如果您需要我澄清任何事情,请告诉我,并提前感谢您的光临。

4 个答案:

答案 0 :(得分:3)

我已经阅读了一些关于此的内容,此处有一些SO帖子以及此链接: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网址,而我的网站恰好是而不是 https。 ..

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

编辑:这个错误信息实际上是误导性的,它只是模糊地表示:你没有以正确的方式使用youtube API:)

答案 1 :(得分:2)

@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进行了一些未经宣布的修改,改变了一些静态变量的位置。

答案 2 :(得分:1)

此错误属于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"
}

古德勒克。

答案 3 :(得分:0)

我的解决方案是将所有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干扰事件&#39; OnStateChange&#39;,我们无法删除此依赖项。 使用jsfiddle对于重现问题没有用,因为它几乎没有依赖性。 我的应用程序是在Rails中构建的,并使用此插件显示视频播放列表:https://github.com/Giorgio003/Youtube-TV/