- Общение окон с разных доменов: postMessage
- Отправитель: метод postMessage
- Получатель: событие onmessage
- Итого
- Window.postMessage()
- Syntax
- The dispatched event
- Security concerns
- Secure shared memory messaging
- Example
- Notes
- Using window.postMessage in extensions This API has not been standardized.
- PostMessageA function (winuser.h)
- Syntax
- Parameters
- Return value
- Remarks
- Examples
- Post message between windows
Общение окон с разных доменов: postMessage
Материал на этой странице устарел, поэтому скрыт из оглавления сайта.
Более новая информация по этой теме находится на странице https://learn.javascript.ru/cross-window-communication.
Интерфейс postMessage позволяет общаться друг с другом окнам и ифреймам с разных доменов.
Он очень удобен, например, для взаимодействия внешних виджетов и сервисов, подключённых через ифрейм с основной страницей.
Отправитель: метод postMessage
Первая часть интерфейса состоит из метода postMessage. Его вызывает окно, которое хочет отправить сообщение, в контексте окна-получателя.
Проще говоря, если мы хотим отправить сообщение в окно win , то нужно вызвать win.postMessage(data, targetOrigin) .
Данные. По спецификации, это может быть любой объект, который будет клонирован с сохранением структуры при передаче.
Но IE поддерживает только строки, поэтому обычно данные JSON-сериализуют.
Разрешить получение сообщения только окнам с данного источника.
Мы ведь не можем из JavaScript узнать, на каком именно URL находится другое окно. Но иногда хочется быть уверенным, что данные передаются в доверенный документ. Для этого и нужен этот параметр. Проверку осуществляет браузер. При указании ‘*’ ограничений нет.
В браузере IE, интерфейс postMessage работает только с ифреймами. Он не работает между табами и окнами.
Это ошибка в данном конкретном браузере, в других – всё в порядке. Детали по этой и связанным с ней ошибкам: HTML5 Implementation Issues in IE8 and later.
Получатель: событие onmessage
Чтобы получить сообщение, окно должно поставить обработчик на событие onmessage .
Свойства объекта события:
data Присланные данные origin Источник, из которого пришло сообщение, например http://javascript.ru . source Ссылка на окно, с которого пришло сообщение. Можно тут же ответить.
Назначать обработчик нужно обязательно через методы addEventListener/attachEvent , например:
Задержки между отправкой и получением нет, совсем.
Если для setTimeout стандарт предусматривает минимальную задержку 4 мс, то для postMessage она равна 0 мс. Поэтому postMessage можно, в том числе, использовать как мгновенную альтернативу setTimeout .
Итого
Интерфейс postMessage позволяет общаться окнам и ифреймам с разных доменов (в IE8 – только ифреймы), при этом обеспечивая проверки безопасности.
Window.postMessage()
The window.postMessage() method safely enables cross-origin communication between Window objects; e.g., between a page and a pop-up that it spawned, or between a page and an iframe embedded within it.
Normally, scripts on different pages are allowed to access each other if and only if the pages they originate from share the same protocol, port number, and host (also known as the «same-origin policy»). window.postMessage() provides a controlled mechanism to securely circumvent this restriction (if used properly).
Broadly, one window may obtain a reference to another (e.g., via targetWindow = window.opener ), and then dispatch a MessageEvent on it with targetWindow.postMessage() . The receiving window is then free to handle this event as needed. The arguments passed to window.postMessage() (i.e., the “message”) are exposed to the receiving window through the event object.
Syntax
The dispatched event
A window can listen for dispatched messages by executing the following JavaScript:
The properties of the dispatched message are:
data The object passed from the other window. origin The origin of the window that sent the message at the time postMessage was called. This string is the concatenation of the protocol and «://», the host name if one exists, and «:» followed by a port number if a port is present and differs from the default port for the given protocol. Examples of typical origins are https://example.org (implying port 443 ), http://example.net (implying port 80 ), and http://example.com:8080 . Note that this origin is not guaranteed to be the current or future origin of that window, which might have been navigated to a different location since postMessage was called. source A reference to the window object that sent the message; you can use this to establish two-way communication between two windows with different origins.
Security concerns
If you do not expect to receive messages from other sites, do not add any event listeners for message events. This is a completely foolproof way to avoid security problems.
If you do expect to receive messages from other sites, always verify the sender’s identity using the origin and possibly source properties. Any window (including, for example, http://evil.example.com ) can send a message to any other window, and you have no guarantees that an unknown sender will not send malicious messages. Having verified identity, however, you still should always verify the syntax of the received message. Otherwise, a security hole in the site you trusted to send only trusted messages could then open a cross-site scripting hole in your site.
Always specify an exact target origin, not * , when you use postMessage to send data to other windows. A malicious site can change the location of the window without your knowledge, and therefore it can intercept the data sent using postMessage .
Secure shared memory messaging
If postMessage() throws when used with SharedArrayBuffer objects, you might need to make sure you cross-site isolated your site properly. Shared memory is gated behind two HTTP headers:
- Cross-Origin-Opener-Policy with same-origin as value (protects your origin from attackers)
- Cross-Origin-Embedder-Policy with require-corp as value (protects victims from your origin)
To check if cross origin isolation has been successful, you can test against the crossOriginIsolated property available to window and worker contexts:
See also Planned changes to shared memory which is starting to roll out to browsers (Firefox 79, for example).
Example
Notes
Any window may access this method on any other window, at any time, regardless of the location of the document in the window, to send it a message. Consequently, any event listener used to receive messages must first check the identity of the sender of the message, using the origin and possibly source properties. This cannot be overstated: Failure to check the origin and possibly source properties enables cross-site scripting attacks.
As with any asynchronously-dispatched script (timeouts, user-generated events), it is not possible for the caller of postMessage to detect when an event handler listening for events sent by postMessage throws an exception.
After postMessage() is called, the MessageEvent will be dispatched only after all pending execution contexts have finished. For example, if postMessage() is invoked in an event handler, that event handler will run to completion, as will any remaining handlers for that same event, before the MessageEvent is dispatched.
The value of the origin property of the dispatched event is not affected by the current value of document.domain in the calling window.
For IDN host names only, the value of the origin property is not consistently Unicode or punycode; for greatest compatibility check for both the IDN and punycode values when using this property if you expect messages from IDN sites. This value will eventually be consistently IDN, but for now you should handle both IDN and punycode forms.
The value of the origin property when the sending window contains a javascript: or data: URL is the origin of the script that loaded the URL.
Using window.postMessage in extensions This API has not been standardized.
window.postMessage is available to JavaScript running in chrome code (e.g., in extensions and privileged code), but the source property of the dispatched event is always null as a security restriction. (The other properties have their expected values.)
It is not possible for content or web context scripts to specify a targetOrigin to communicate directly with an extension (either the background script or a content script). Web or content scripts can use window.postMessage with a targetOrigin of «*» to broadcast to every listener, but this is discouraged, since an extension cannot be certain the origin of such messages, and other listeners (including those you do not control) can listen in.
Content scripts should use runtime.sendMessage to communicate with the background script. Web context scripts can use custom events to communicate with content scripts (with randomly generated event names, if needed, to prevent snooping from the guest page).
Lastly, posting a message to a page at a file: URL currently requires that the targetOrigin argument be «*» . file:// cannot be used as a security restriction; this restriction may be modified in the future.
PostMessageA function (winuser.h)
Places (posts) a message in the message queue associated with the thread that created the specified window and returns without waiting for the thread to process the message.
To post a message in the message queue associated with a thread, use the PostThreadMessage function.
Syntax
Parameters
A handle to the window whose window procedure is to receive the message. The following values have special meanings.
Value | Meaning |
---|---|
HWND_BROADCAST ((HWND)0xffff) | The message is posted to all top-level windows in the system, including disabled or invisible unowned windows, overlapped windows, and pop-up windows. The message is not posted to child windows. |
NULL | The function behaves like a call to PostThreadMessage with the dwThreadId parameter set to the identifier of the current thread. |
В
Starting with Windows Vista, message posting is subject to UIPI. The thread of a process can post messages only to message queues of threads in processes of lesser or equal integrity level.
The message to be posted.
For lists of the system-provided messages, see System-Defined Messages.
Additional message-specific information.
Additional message-specific information.
Return value
If the function succeeds, the return value is nonzero.
If the function fails, the return value is zero. To get extended error information, call GetLastError. GetLastError returns ERROR_NOT_ENOUGH_QUOTA when the limit is hit.
Remarks
When a message is blocked by UIPI the last error, retrieved with GetLastError, is set to 5 (access denied).
Messages in a message queue are retrieved by calls to the GetMessage or PeekMessage function.
Applications that need to communicate using HWND_BROADCAST should use the RegisterWindowMessage function to obtain a unique message for inter-application communication.
The system only does marshalling for system messages (those in the range 0 to (WM_USER-1)). To send other messages (those >= WM_USER) to another process, you must do custom marshalling.
If you send a message in the range below WM_USER to the asynchronous message functions (PostMessage, SendNotifyMessage, and SendMessageCallback), its message parameters cannot include pointers. Otherwise, the operation will fail. The functions will return before the receiving thread has had a chance to process the message and the sender will free the memory before it is used.
Do not post the WM_QUIT message using PostMessage; use the PostQuitMessage function.
An accessibility application can use PostMessage to post WM_APPCOMMAND messages to the shell to launch applications. This functionality is not guaranteed to work for other types of applications.
A message queue can contain at most 10,000 messages. This limit should be sufficiently large. If your application exceeds the limit, it should be redesigned to avoid consuming so many system resources. To adjust this limit, modify the following registry key.
The minimum acceptable value is 4000.
Examples
The following example shows how to post a private window message using the PostMessage function. Assume you defined a private window message called WM_COMPLETE:
You can post a message to the message queue associated with the thread that created the specified window as shown below:
The winuser.h header defines PostMessage as an alias which automatically selects the ANSI or Unicode version of this function based on the definition of the UNICODE preprocessor constant. Mixing usage of the encoding-neutral alias with code that not encoding-neutral can lead to mismatches that result in compilation or runtime errors. For more information, see Conventions for Function Prototypes.
Post message between windows
Using postMessage, a new feature in HTML5 to securely communicate between parent and child window, to post messages between windows & iframes.
The Window.postMessage() method safely enables cross-origin communication. Normally, scripts on different pages are allowed to access each other if and only if the pages that executed them are at locations with the same protocol (usually both https), port number (443 being the default for https), and host (modulo Document.domain being set by both pages to the same value). window.postMessage() provides a controlled mechanism to circumvent this restriction in a way which is secure when properly used.
The window.postMessage() method, when called, causes a MessageEvent to be dispatched at the target window when any pending script that must be executed completes (e.g., remaining event handlers if window.postMessage() is called from an event handler, previously-set pending timeouts, etc.) The MessageEvent has the type message, a data property which is set to the value of the first argument provided to window.postMessage(), an origin property corresponding to the origin of the main document in the window calling window.postMessage at the time window.postMessage() was called, and a source property which is the window from which window.postMessage() is called. (Other standard properties of events are present with their expected values.)
This is Enclosing App (we can say iFrame hosting/parent app). It will embedd an iFrame in its DOM and send a message to iFrame using postMessage. EA has been configured to receive message from iFrameApp as well and display it accordingly.
This app will be load in iFrame, embedded in Enclosing App. It will receive an message from EA and process it. It will also send separate message to EA.