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

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

На моем сайте есть проигрыватель JavaScript, который воспроизводит списки песен, которые можно разместить на YouTube, SoundCloud или Vimeo. Вчера я заметил эту ошибку, которая обычно возникает всякий раз, когда вы пытаетесь загрузить новую песню через "пропуск" с помощью кнопок плеера. Эта ошибка только началась в последний день или два. Я не вижу ничего нового в примечаниях к выпуску youtube api, и эта ошибка возникает при использовании 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 Java YouTube:

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 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 ответа

Решение

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

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

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

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

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

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

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

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

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

РЕДАКТИРОВАТЬ: это сообщение об ошибке вводит в заблуждение на самом деле, это только смутно означает: вы не используете 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 на отдельной странице (настолько пустой, насколько это возможно), и на эту страницу можно ссылаться в виде 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/)

Другие вопросы по тегам