Как отмечалось в разделе 14.8, некоторые окна и вкладки броузера полностью изолированы друг от друга, и сценарий, выполняющийся в одном окне или вкладке, ничего не знает о существовании других окон и вкладок. В других случаях, когда сценарий сам открывает новые окна или работает с вложенными фреймами, сценарии в этих окнах и фреймах могут быть осведомлены друг о друге. Если эти окна или фреймы содержат документы, полученные от одного и того же веб-сервера, сценарии в этих окнах и фреймах смогут взаимодействовать друг с другом и манипулировать документами друг друга.
Однако иногда сценарий имеет возможность сослаться на другой объект
Window
, но, поскольку содержимое этого окна имеет иное происхождение, веб-броузер (следующий
требованиям политики общего происхождения) не позволит сценарию просматривать содержимое документа в этом другом окне. Броузер не позволит сценарию читать значения свойств или вызывать методы другого окна. Единственный метод окна, который может вызвать сценарий из документа с другим происхождением, называется
postMessage,
и этот метод обеспечивает возможность ограниченных взаимодействий - в форме асинхронных сообщений - между сценариями из документов с разным происхождением. Этот вид взаимодействий определяется стандартом HTML5 и реализован во всех текущих броузерах (включая ІЕ8 и более поздние версии). Этот прием известен как «обмен сообщениями между документами с разным происхождением», но, так как прикладной интерфейс поддержки определен в объекте
Window
, а не в объекте документа, возможно, лучше было бы назвать этот прием «обменом сообщениями между окнами».
Метод
postMessage
принимает два обязательных аргумента. Первый - передаваемое сообщение. Согласно спецификации HTML5, это может быть любое простое значение или объект, который можно скопировать (смотрите врезку «Структурированные копии» выше), но некоторые текущие броузеры (включая Firefox 4 beta) принимают только строки, поэтому, если в сообщении потребуется передать объект или массив, его необходимо будет предварительно сериализовать с помощью функции
JSON.stringify
(раздел 6.9).
Во втором аргументе должна передаваться строка, определяющая ожидаемое происхождение окна, принимающего сообщение. Эта строка должна включать протокол, имя хоста и (необязательно) номер порта (можно передать полный URL-адрес, но все, кроме протокола, хоста и порта будет игнорироваться). Это предусмотрено из соображений безопасности: злонамеренный программный код или обычные пользователи могут открывать новые окна с документами, взаимодействие с которыми вы не предполагали, поэтому
postMessage
не будет доставлять ваши сообщения, если окно будет содержать документ с происхождением, отличным от указанного. Если передаваемое сообщение не содержит конфиденциальной информации и вы готовы передать ее сценарию из документа с любым происхождением, то во втором аргументе можно передать строку "*", которая будет играть роль шаблонного символа. Если необходимо указать, что документ должен иметь то же происхождение, что и документ в текущем окне, можно передать строку "/".
Если происхождение документа совпадет с указанным в аргументе, вызов метода
postMessage
приведет к возбуждению события «message» в целевом объекте
Window
. Сценарий в этом окне может определить обработчик для обработки событий «message», которому будет передан объект события со следующими свойствами:
data
Копия сообщения, переданного методу postMessage в первом аргументе.
source
Объект
Window
, из которого было отправлено сообщение.
origin
Строка, определяющая происхождение (в виде URL) документа, отправившего сообщение.
Большинство обработчиков
onmessage
должно сначала проверить свойство
origin
своего аргумента и должно игнорировать сообщения из неподдерживаемых доменов.
Обмен сообщениями с документами из сторонних доменов посредством метода
postMessage
и обработки события «message» может пригодиться, например, когда необходимо подключить к веб-странице модуль, или «гаджет», с другого сайта. Если модуль достаточно прост и автономен, его можно просто загрузить в элемент
<iframe>.
Однако представьте, что это более сложный модуль, который определяет свой прикладной интерфейс, и ваша веб-страница должна управлять этим модулем или как-то иначе взаимодействовать с ним. Если модуль определен в виде элемента
<script>,
он сможет предложить полноценный прикладной интерфейс на языке JavaScript, но, с другой стороны, включение его в страницу даст ему полный контроль над страницей и ее содержимым. Такой подход широко используется в современной Всемирной паутине (особенно в веб-рекламе), но в действительности это не самое лучшее решение, даже если вы доверяете другому сайту.
Альтернативой является обмен сообщениями между документами с разным происхождением: автор модуля может упаковать его в HTML-файл, который принимает события «message» и передает их для обработки соответствующим функциям на языке JavaScript. В этом случае веб-страница, подключившая модуль, сможет взаимодействовать с ним, отправляя сообщения с помощью метода
postMessage.
Этот прием демонстрируется в примерах 22.4 и 22.5. В примере 22.4 приводится реализация простого модуля, подключаемого с помощью элемента
<iframe>
, который выполняет поиск на сайте Twitter и отображает сообщения, соответствующие указанной фразе. Чтобы выполнить поиск с помощью этого модуля, подключившая его страница должна просто отправить ему сообщение с требуемой фразой.
Пример 22.4. Модуль поиска на сайте Twitter с помощью метода
postMessage
<!DOCTYPE html>
<! —
Это модуль поиска на сайте Twitter. Модуль можно подключить к любой странице внутри элемента <iframe> и запросить его выполнить поиск, отправив ему строку запроса с помощью метода postMessage. Поскольку модуль подключается в элементе <iframe>, а не <script>, он не сможет получить доступ к содержимому вмещающего документа.
– ->
<html>
<head>
<style>body { font: 9pt sans-serif: }</style>
<!-- Подключить библиотеку jQuery ради ее утилиты jQuery.getJSON -->