Не удалось выполнить 'postMessage' в 'DOMWindow': несоответствие цели / источника http vs https
Я заранее прошу прощения, потому что меня очень смущает моя проблема. Я действительно в затруднении, потому что это вызывает проблему на моей производственной площадке.
На моем сайте есть проигрыватель JavaScript, который воспроизводит списки песен, которые можно разместить на YouTube, SoundCloud или Vimeo. Вчера я заметил эту ошибку, которая обычно возникает всякий раз, когда вы пытаетесь загрузить новую песню через "пропуск" с помощью кнопок плеера. Эта ошибка только началась в последний день или два. Я не вижу ничего нового в примечаниях к выпуску youtube api, и эта ошибка возникает при использовании Chrome, Firefox и Safari, поэтому, скорее всего, она не связана с изменениями в браузере. Что-то, что я использую, изменилось, хотя, поскольку я не выдвигал новый код в течение 18 дней.
Пример плейлиста находится здесь: http://www.muusical.com/playlists/programming-music
Я думаю, что я выделил способ воспроизвести ошибку, вот шаги:
- Слушать песню на YouTube.
- Перейдите к любой другой песне в списке (нажатием кнопок пропуска или прямым нажатием кнопки воспроизведения на элементе строки песни).
* Обратите внимание, что если первая песня в списке воспроизведения является песней 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&enablejsapi=1&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/)