JavaScript中的window.postMessage


本文作者: jsweibo

本文链接: https://jsweibo.github.io/2020/06/20/JavaScript%E4%B8%AD%E7%9A%84window-postMessage/

摘要

本文主要讲述了:

  1. 作用
  2. 参数

正文

作用

向跨源的父页面或子页面发送消息

示例:

a.foo.com/index.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<h1>a.foo.com</h1>
<button id="openNewTab" type="button">Open new tab</button>
<button id="sendMsg" type="button">Send Message</button>
<script>
let childWindow;
window.addEventListener('message', function (event) {
console.log(event);
});
document
.querySelector('#openNewTab')
.addEventListener('click', function () {
childWindow = open('http://b.foo.com/index.html');
});
document.querySelector('#sendMsg').addEventListener('click', function () {
childWindow.postMessage('hello, jsweibo', 'http://b.foo.com');
});
</script>
</body>
</html>

b.foo.com/index.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<h1>b.foo.com</h1>
<button id="sendMsg" type="button">Send Message</button>
<script>
window.addEventListener('message', function (event) {
console.log(event);
});
document.querySelector('#sendMsg').addEventListener('click', function () {
opener.postMessage('hi, world', 'http://a.foo.com');
});
</script>
</body>
</html>

参数

targetWindow.postMessage(message, targetOrigin)

targetWindow

目标网页的window对象

例如:

  • top
  • parent
  • opener
  • open()
  • <iframe>contentWindow

message

需要发送的消息

JavaScript 运行时将使用结构化克隆算法处理message

注意:结构化克隆算法无法克隆函数,因此message内不得包含函数、函数数组

targetOrigin

目标网页的origin

默认值为*

注意:支持但不推荐将targetOrigin设置为*,因为这很可能会导致非常严重的安全问题。

示例:此页面将向任意的父页面发送消息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<button id="sendMsg" type="button">Send Message</button>
<script>
document.querySelector('#sendMsg').addEventListener('click', function () {
opener.postMessage('hello, jsweibo', '*');
});
</script>
</body>
</html>

为什么要手动设置 targetOrigin

发送消息的方式为targetWindow.postMessage(message, targetOrigin),为什么targetWindow.postMessage()不去自动获取targetWindow.location.origin,反而让开发者手动传递targetOrigin呢?

原因很简单,由于同源政策的限制,在跨源通信中,无法访问targetWindow.location.origin

父页面必然是通过<iframe>open()等方式打开子页面的,因此父页面肯定知道targetWindow和 URL。尽管由于同源政策的限制,在跨源通信中,无法访问targetWindow.location.origin,但根据 URL 解析出targetOrigin也不是难事。因此手动设置targetOrigin根本不能阻止开发者向跨源子页面发送消息。那为什么还要手动传递targetOrigin呢?

原因很简单,以上的想法都是站在父页面向跨源子页面发送消息的角度来考虑的,现在请考虑子页面向跨源父页面发送消息的场景。由于同源政策的限制,在跨源通信中,子页面无法访问opener.location.origin。如果不配置targetOrigin或将其配置为*,子页面将向任意的父页面发送消息,这很可能会导致非常严重的安全问题。

参考资料

本文作者: jsweibo

本文链接: https://jsweibo.github.io/2020/06/20/JavaScript%E4%B8%AD%E7%9A%84window-postMessage/


本文对你有帮助?请支持我


支付宝
微信