Не удалось выполнить 'postMessage' на 'DOMWindow': несоответствие цели / источника http vs https


Я заранее приношу свои извинения, так как я очень запутался в своей проблеме. Я действительно в затруднительном положении, потому что это вызывает проблемы на моем производственном участке.

У меня есть javascript-плеер на моем сайте, который воспроизводит списки песен, которые могут быть размещены на youtube, soundcloud или vimeo. Вчера я заметил эту ошибку, которая обычно возникает всякий раз, когда вы пытаетесь загрузить новую песню через "пропуск" с помощью кнопок проигрывателя. Эта ошибка только началась в последние день или два. Я не вижу в этом ничего нового. YouTube api release notes и эта ошибка возникает при использовании Chrome, Firefox и Safari, поэтому она, скорее всего, не связана с изменением браузера. Что-то, что я использую, изменилось, хотя, поскольку я не нажимал новый код в течение 18 дней.

Пример плейлиста здесь: http://www.muusical.com/playlists/programming-music

Я думаю, что выделил способ воспроизвести ошибку, вот шаги:

  1. воспроизведение песни, размещенной на youtube.
  2. перейти к любому другому песня в списке (либо нажатием кнопки пропустить, либо прямым нажатием кнопки воспроизвести в строке песни).

*Обратите внимание, что если первая песня в плейлисте является песней 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').

Я загружаю плеер с помощью API YouTube javascript:

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.

Кроме того, вот как я загружаю javascript youtube:

// 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 2

4 ответа:

Я немного читал об этом, некоторые так посты здесь и там, и эта ссылка тоже: https://code.google.com/p/gdata-issues/issues/detail?id=5788

Я собирался добавить комментарий к вашему вопросу, сказав, что схожу с ума от этого ... но когда я начал описывать свою установку,я нашел способ избежать этой проблемы.

Я начинаю с пустого элемента div и использую API Youtube Iframe, чтобы превратить его в iframe со всеми необходимыми опциями.

У меня есть несколько дивы, подобные этому, обычно используют одну и ту же переменную JS для хранения всех этих игроков, но по одному (один заменяет другого и т. д... - могло быть и лучше, я знаю).

Чтобы исправить проблему, у меня была идея уничтожить игрока с youtubePlayer.destroy();, прежде чем построить новый из другого элемента. Больше никаких ошибок JS, кровоточащих в моей консоли Chrome:).

Надеюсь, это поможет, вся литература, которую я мог прочитать о http и https, не применима к моему случаю, потому что я не устанавливаю iframe URL сам, и мой сайт, оказывается, не https ...

Я восстановил асинхронный вызов вместо статического тега script в моем HTML, но я не думаю, что это было необходимо.

EDIT : это сообщение об ошибке довольно вводит в заблуждение на самом деле, это только смутно означает : вы не используете API youtube должным образом :)

Ответ@sodawillow частично верен, но я хотел бы подробно рассказать о решении и о том, что заставило мой код перестать вызывать метод .destroy() для удаления проигрывателя youtube.

На моем сайте есть плеер, который меняет местами песни с различных сайтов, одним из которых является Youtube. Существуют различные способы удаления игрока в зависимости от его типа. Мой код проверяет наличие проигрывателя youtube, и если он проходит проверку, то он использует метод .destroy(), который только проигрыватель YouTube имеет. Проблема в том, что YouTube изменил имена некоторых статических переменных в своем объекте player. Например, если я создал игрока через:
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, изменив расположение некоторых статических переменных.

Эта ошибка относится к API Google Youtube.

Внутри "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"
}

Гудлак.

Мое решение состоит в том , чтобы записать всю логику плеера Youtube на отдельной странице (такой же пустой, как и possible), и на эту страницу ссылаться в теге 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>

(как Примечание На полях: мой контекст-это прототип.js вмешивается в событие OnStateChange, и мы не можем удалить эту зависимость. Использование jsfiddle не было бы полезно для воспроизведения проблемы, так как оно имеет мало зависимостей. Мое приложение здесь встроено в Rails, и с помощью этого плагин для показа плейлиста Видео: https://github.com/Giorgio003/Youtube-TV/)