Решение проблемы с cross-origin postMessage в IE10
Быстрый ответ
Для правильного использования postMessage
в IE10 укажите конкретный целевой источник (origin) и проведите проверку источника отправителя. Ваш инструментарий для исправления ситуации выглядит так:
// Окно отправителя, готовое к общению
window.opener.postMessage('Сообщение', 'https://receiver.example.com');
// Окно получателя, с установленной защитой
window.addEventListener('message', (e) => {
if (e.origin === 'https://sender.example.com') { // Осторожность не повредит
console.log(e.data); // ...Отлично, давайте посмотрим, что нам пришло
}
}, false);
Детальное руководство по работе с postMessage в IE10
Использование MessageChannel в IE10
postMessage
обычно работает без сбоев, однако, IE10 иногда может преподнести сюрпризы. API MessageChannel
предоставляет структуру, которая надежно функционирует в IE10:
let channel = new MessageChannel();
let iframe = document.getElementById('myIframe').contentWindow;
// Отправляем сообщение через port2 и ожидаем ответ в port1
channel.port1.onmessage = function(event) {
console.log(event.data); // Как есть, без загадок
};
iframe.postMessage('Привет', '*', [channel.port2]); // Отправляем сигнал в космос. Но не забывайте указывать конкретный целевой источник в реалиях продакшена.
Подробную информацию вы найдете в документации MessageChannel на MSDN.
Альтернативный подход с использованием iframe и прокси-страницы
Если MessageChannel
кажется вам неуместным, вы можете использовать прокси-страницу на том же домене, где находится отправитель. С помощью продвинутого iframe можно передать сообщение:
// Создаём элемент iframe просто так
let iframe = document.createElement('iframe');
iframe.src = 'https://proxy.example.com/proxy.html'; // Мы в прямом эфире
document.body.appendChild(iframe);
// В proxy.html
window.addEventListener('message', (e) => {
if (e.data && e.source) {
let targetWindow = window.open('', 'targetWindowName');
targetWindow.postMessage(e.data, 'https://target.example.com'); // Сюрпризы продолжаются
}
});
Регулярная отправка сообщений с помощью setInterval
Желаете наладить стабильный обмен сообщениями? Сочетание функций postMessage
и setInterval
идеально подойдёт для этой цели:
setInterval(function() {
let targetWindow = window.open('', 'targetWindowName');
targetWindow.postMessage('Периодическое сообщение', 'https://target.example.com'); // Тук-тук. Кто там? Еще одно сообщение.
}, 5000); // Точно как по часам, каждые 5 секунд
Убедитесь, что окно-получатель настроено на прием сообщений. И помните о важности проверки источника сообщения!
Пересылка объектов с использованием JSON.stringify()
Не забывайте преобразовывать ваши объекты перед отправкой с помощью JSON.stringify()
:
let myBag = { essentials: "packed" };
let targetWindow = window.open('https://target.example.com');
targetWindow.postMessage(JSON.stringify(myBag), '*'); // В путь!
И обратно, после прибытия:
window.addEventListener('message', (e) => {
let unpackedBag = JSON.parse(e.data);
// Здесь доступ к распакованным сокровищам
});
Визуализация
Процесс работы кросс-доменного postMessage в IE10:
Остров A (🏝️ A)
: отправляет сообщение в бутылке (📩
)
Остров B (🏝️ B)
: ожидает получения сообщения
Ожидание
: 🏝️ A 🌊 📩 ➡️ 🌊 🏝️ B
Реальность в IE10
: 🏝️ A 🌊 📩 ✖️ 🚫
Распространенные приемы для бесперебойной работы
Обеспечьте совместимость с различными браузерами
postMessage
прекрасно работает с новыми браузерами, но всегда делайте перекрестные проверки. Возможно, потребуется добавить проверку методов вроде addEventListener
для устаревших браузеров:
if (window.attachEvent) { // О, те времена, IE8
window.attachEvent('onmessage', handleMessage);
} else {
window.addEventListener('message', handleMessage, false);
}
С учетом прошлого: проверяйте отправителя
С postMessage
нужно быть настороже. Осторожность никогда не повредит:
function handleMessage(event) {
if (event.origin !== 'https://trusted.example.com') {
// Стоп, не поехали!
return;
}
// Всё идеально, можно продолжить
}
Аккуратно закрывайте окна
Не забывайте закрывать окна после того, как они выполнили свою функцию. Ведь они могут остаться открытыми:
let remoteWindow = window.open('https://target.example.com', 'RemoteWindow');
// Диалог завершен...
remoteWindow.close(); // До свидания, Фелиция
Полезные материалы
- Window postMessage() – Веб-API | MDN — Инструкции MDN по
postMessage
. - HTML Living Standard — Официальная спецификация HTML от WHATWG.
- "postMessage" на Can I use... — Таблица совместимости браузеров для
postMessage
. - DOM Exception 12 для window.postMessage – Stack Overflow — Обсуждение проблем и их решений для
postMessage
. - Способы обхода политики одного происхождения – Stack Overflow — Полезная информация о кросс-доменном обмене информацией.