Использование JavaScript и window.postMessage()

Использование JavaScript и window.postMessage()

От автора: кросс-доменная связь (также называемая Cross-origin) может представлять угрозу безопасности. Однако в HTML5 есть полезная и часто упускаемая возможность window.postMessage(), которая при правильном использовании безопасна.

Как указано в MDN, — Метод window.postMessage() безопасно обеспечивает перекрестную связь между объектами Window; например, между страницей и всплывающим окном или между страницей и встроенным в нее фреймом.

В этой статье мы рассмотрим связи между окнами, а не окна с фреймом. Кстати, в определении MDN указано всплывающее окно, которое мы будем использовать, но оно не обязательно должно быть всплывающим.

Два обязательных компонента и их синтаксис

Два обязательных компонента:

window.postMessage() — отправляет сообщение

window.addEventListener(« message », callback ) — для получения и обработки сообщения

Синтаксис для метода postMessage():

targetWindow.postMessage(message, targetOrigin, [transfer]);

Существует необязательный третий параметр [transfer], который мы не будем использовать. Вы можете прочитать больше о нем на MDN.

targetWindow — это обработчик для окна, в которое вы хотите отправить сообщение.

message может представлять собой довольно много сложных объектов. Однако функции не могут быть отправлены как часть сообщения, поскольку данные сообщения сериализуются с использованием алгоритма структурированного клонирования. Алгоритм структурированного клонирования не учитывает функции. Однако это означает, что вы можете безопасно передавать широкий спектр объектов данных.

targetOrigin — очень важная часть. Это URI страницы получателя. В момент отправки (postMessage), если targetOrigin действительно совпадает с именем хоста страницы targetWindow, он не сможет отправить сообщение.
Можно использовать «*» в качестве целевого идентификатора, но делайте это только для простого тестирования (как мы будем делать здесь).

Хочу особо подчеркнуть, в процессе производства на принимающей стороне вам нужно проверить домен получателей по отношению к targetOrigin. Если они не совпадают, не принимайте сообщение.

Предостережение: если в качестве targetOrigin используется «*», сообщение может быть откуда угодно. Имейте в виду, что мы обычно отправляем сообщение из одного домена в другой, поэтому targetOrigin должен соответствовать домену получателя targetWindow.

Другими словами, мы можем захотеть отправить сообщение с https://abcd.com на https://defg.com.Таким образом, targetOrigin будет https://defg.com, а домен получателя будет https://defg.com.

Пример

Мы создадим две веб-страницы с именами Page1.html и Page2.html. Page2.html будет всплывающим окном, что не обязательно, это просто мой выбор. Page1.html отправит сообщение на страницу Page2.html.

Создайте следующие файлы. Page1.html (обратите внимание на функцию sendMessage)

<!DOCTYPE html>
<html>
<head> <title></title> <meta charset="utf-8" />
<script>var childwin;
const childname = "popup";
function openChild() {childwin = window.open('Page2.html', childname, 'height=300px, width=500px'); }
function sendMessage(){ let msg={pName : "Bob", pAge: "35"}; // In production, DO NOT use '*', use toe target domain childwin.postMessage(msg,'*')// childwin is the targetWindow childwin.focus();
}</script>
</head>
<body> <form> <fieldset> <input type='button' id='btnopen' value='Open child' onclick='openChild();' /> <input type='button' id='btnSendMsg' value='Send Message' onclick='sendMessage();' /> </fieldset> </form>
</body>
</html>

Page2.html (обратите внимание на функцию обратного вызова в addEventListener)

<!DOCTYPE html>
<html>
<head> <title></title> <meta charset="utf-8" /> <script>// Allow window to listen for a postMessage window.addEventListener("message", (event)=>{// Normally you would check event.origin // To verify the targetOrigin matches // this window's domain let txt=document.querySelector('#txtMsg'); // event.data contains the message sent txt.value=`Name is ${event.data.pName} Age is ${event.data.pAge}` ; });function closeMe() { try {window.close(); } catch (e) { console.log(e) } try {self.close(); } catch (e) { console.log(e) }} </script>
</head>
<body> <form> <h1>Recipient of postMessage</h1> <fieldset> <input type='text' id='txtMsg' /> <input type='button' id='btnCloseMe' value='Close me' onclick='closeMe();' /> </fieldset> </form>
</body>
</html>

Тестовый прогон

Откройте Page1.html и нажмите кнопку «Open child». Она открывает всплывающее окно.

Всплывающее окно

Нажмите кнопку «Send Message». Сообщение получено во всплывающем окне.

Результат childwin.postMessage()

Что происходит?

При нажатии «Send Message» объект отправляется на страницу получателя с использованием ссылки на это окно childwin, созданной во время window.open().

childwind.postMessage(msg,”*”)

Опять же, НЕ используйте «*» для других случаев, кроме тестирования. TargetOrigin должен быть доменом, в котором находится страница получателя.

Прослушиватель событий окна получателя получает сообщение в параметре с именем «event». Функция обратного вызова, в нашем случае функция Arrow, обрабатывает сообщение.

Сообщение содержится в event.data

TargetOrigin содержится в event.origin

Заключение

window.postMessage() — это безопасный способ отправки сообщений между окнами в разных доменах или источниках. Их можно также публиковать в IFrame.

Отправляемые данные сериализуются с использованием алгоритма структурированного клонирования и принимают практически любой тип простых или сложных данных.

Существует также postMessage(), его можно использовать, когда контекст браузера одинаков. Это связано с каналом.
channel.postMessage() будет рассмотрен в другой статье. Спасибо за чтение и удачного кодирования!

Автор: gravity well

Источник: https://medium.com

Редакция: Команда webformyself.