5.6 KiB
Общение окон с разных доменов: postMessage
Интерфейс postMessage
позволяет общаться друг с другом окнам и ифреймам с разных доменов.
Он очень удобен, например, для взаимодействия внешних виджетов и сервисов, подключённых через ифрейм с основной страницей. [cut]
Отправитель: метод postMessage
Первая часть интерфейса состоит из метода postMessage. Его вызывает окно, которое хочет отправить сообщение, в контексте окна-получателя.
Проще говоря, если мы хотим отправить сообщение в окно win
, то нужно вызвать win.postMessage(data, targetOrigin)
.
Аргументы:
- data
- Данные. По спецификации, это может быть любой объект, который будет *клонирован с сохранением структуры* при передаче.
Но IE поддерживает только строки, поэтому обычно данные JSON-сериализуют.
- targetOrigin
- Разрешить получение сообщения только окнам с данного источника.
Мы ведь не можем из JavaScript узнать, на каком именно URL находится другое окно. Но иногда хочется быть уверенным, что данные передаются в доверенный документ. Для этого и нужен этот параметр. Проверку осуществляет браузер. При указании
'*'
ограничений нет.
Например:
<!--+ no-beautify -->
<iframe src="http://target.com" name="target">
<script>
var win = window.frames.target;
win.postMessage("сообщение", "http://javascript.ru");
</script>
[warn header="В IE11- можно использовать postMessage
только для ифреймов"]
В браузере IE, интерфейс postMessage
работает только с ифреймами. Он не работает между табами и окнами.
Это ошибка в данном конкретном браузере, в других -- всё в порядке. Детали по этой и связанным с ней ошибкам: HTML5 Implementation Issues in IE8 and later. [/warn]
Получатель: событие onmessage
Чтобы получить сообщение, окно должно поставить обработчик на событие onmessage
.
Свойства объекта события:
- `data`
- Присланные данные
- `origin`
- Источник, из которого пришло сообщение, например `http://javascript.ru`.
- `source`
- Ссылка на окно, с которого пришло сообщение. Можно тут же ответить.
Назначать обработчик нужно обязательно через методы addEventListener/attachEvent
, например:
function listener(event) {
if (event.origin != 'http://javascript.ru') {
// что-то прислали с неизвестного домена - проигнорируем..
return;
}
alert( "получено: " + event.data );
}
if (window.addEventListener) {
window.addEventListener("message", listener);
} else {
// IE8
window.attachEvent("onmessage", listener);
}
[smart header="Задержка отсутствуют"] Задержки между отправкой и получением нет, совсем.
Если для setTimeout
стандарт предусматривает минимальную задержку 4мс, то для postMessage
она равна 0мс.
Поэтому postMessage
можно, в том числе, использовать как мгновенную альтернативу setTimeout
.
[/smart]
Итого
Интерфейс postMessage
позволяет общаться окнам и ифреймам с разных доменов (в IE8 -- только ифреймы), при этом обеспечивая проверки безопасности.
- Отправитель вызывает `targetWin.postMessage(data, targetOrigin)`.
- Если `targetOrigin` не `'*'`, то браузер проверяет, совпадает ли источник с `targetWin`.
- Если совпадает, то на `targetWin` генерируется событие `onmessage`, в котором передаются:
- `origin` -- источник, с которого пришло сообщение.
- `source` -- ссылка на окно-отправитель.
- `data` -- данные. Везде, кроме IE, допустимы объекты, которые клонируются, а в IE -- только строка.
- Обработчик на `onmessage` необходимо вешать при помощи специализированных методов `addEventListener/attachEvent`.