Broadcast Channel API
Broadcast Channel API 可以实现同源下浏览器不同窗口,Tab 页,frame 或者 iframe 下的浏览器上下文 (通常是同一个网站下不同的页面) 之间的简单通讯(此特性在 Web Worker 中可用)。广播频道会被命名和绑定到指定的源
- 实现原理
通过创建一个监听某个频道下的 BroadcastChannel 对象,你可以接收发送给该频道的所有消息。一个有意思的点是,你不需要再维护需要通信的 iframe 或 worker 的索引。它们可以通过构造 BroadcastChannel 来简单地“订阅”特定频道,并在它们之间进行全双工(双向)通信。
- 使用场景
- 在所有标签页上登录或注销用户
- 检测资源何时上传,并在所有页面中展示它
- 指示service worker做一些幕后工作
- 使用方法
- 创建或加入某个频道
- BroadcastChannel 接口非常简单。通过创建一个 BroadcastChannel 对象,一个客户端就加入了某个指定的频道。只需要向 构造函数 传入一个参数:频道名称。如果这是首次连接到该广播频道,相应资源会自动被创建。
var bc = new BroadcastChannel('test_channel');
- BroadcastChannel 接口非常简单。通过创建一个 BroadcastChannel 对象,一个客户端就加入了某个指定的频道。只需要向 构造函数 传入一个参数:频道名称。如果这是首次连接到该广播频道,相应资源会自动被创建。
- 发送消息
- 现在发送消息就很简单了,只需要调用 BroadcastChannel 对象上的postMessage() 方法即可。该方法的参数可以是任意对象。最简单的例子就是发送 DOMString 文本消息:
bc.postMessage('This is a test message.');
不只是 DOMString,任意类型的对象都可以被发送。此 API 不会将消息与任何的语义相关联,因此通道的参与者有必要知道预期的消息类型和消息的消费方式。
- 现在发送消息就很简单了,只需要调用 BroadcastChannel 对象上的postMessage() 方法即可。该方法的参数可以是任意对象。最简单的例子就是发送 DOMString 文本消息:
- 接收消息
- 当消息被发送之后,所有连接到该频道的 BroadcastChannel 对象上都会触发 message 事件。该事件没有默认的行为,但是可以使用 onmessage 事件处理程序来定义一个函数来处理消息。
bc.onmessage = function (ev) { console.log(ev); }
- 当消息被发送之后,所有连接到该频道的 BroadcastChannel 对象上都会触发 message 事件。该事件没有默认的行为,但是可以使用 onmessage 事件处理程序来定义一个函数来处理消息。
- 与频道断开连接
- 通过调用 BroadcastChannel 对象的 close() 方法,可以离开频道。这将断开该对象和其关联的频道之间的联系,并允许它被垃圾回收。
bc.close()
- 通过调用 BroadcastChannel 对象的 close() 方法,可以离开频道。这将断开该对象和其关联的频道之间的联系,并允许它被垃圾回收。
- 创建或加入某个频道
- 参考
window.postMessage
window.postMessage() 方法可以安全地实现跨源通信
从广义上讲,一个窗口可以获得对另一个窗口的引用(比如 targetWindow = window.opener),然后在窗口上调用 targetWindow.postMessage() 方法分发一个 MessageEvent 消息。接收消息的窗口可以根据需要自由处理此事件 (en-US)。传递给 window.postMessage() 的参数(比如 message)将通过消息事件对象暴露给接收消息的窗口。
- 使用方法
- 发送消息
otherWindow.postMessage(message, targetOrigin, [transfer]);
- otherWindow
- 其他窗口的一个引用,比如 iframe 的 contentWindow 属性、执行window.open返回的窗口对象、或者是命名过或数值索引的window.frames (en-US)。
- message
- 将要发送到其他 window 的数据。它将会被结构化克隆算法 (en-US)序列化。这意味着你可以不受什么限制的将数据对象安全的传送给目标窗口而无需自己序列化。
- targetOrigin
- 通过窗口的 origin 属性来指定哪些窗口能接收到消息事件,其值可以是字符串""(表示无限制)或者一个 URI。在发送消息的时候,如果目标窗口的协议、主机地址或端口这三者的任意一项不匹配 targetOrigin 提供的值,那么消息就不会被发送;只有三者完全匹配,消息才会被发送。这个机制用来控制消息可以发送到哪些窗口;例如,当用 postMessage 传送密码时,这个参数就显得尤为重要,必须保证它的值与这条包含密码的信息的预期接受者的 origin 属性完全一致,来防止密码被恶意的第三方截获。如果你明确的知道消息应该发送到哪个窗口,那么请始终提供一个有确切值的 targetOrigin,而不是 *。不提供确切的目标将导致数据泄露到任何对数据感兴趣的恶意站点。
- transfer
- 是一串和 message 同时传递的 Transferable 对象。这些对象的所有权将被转移给消息的接收方,而发送一方将不再保有所有权。
- otherWindow
- 接收消息
window.addEventListener("message", (event) => {}, false);
event 属性:- data: 从其他 window 中传递过来的对象。
- origin:调用 postMessage 时消息发送方窗口的 origin . 这个字符串由 协议、“😕/“、域名、“ : 端口号”拼接而成。例如“https://example.org (隐含端口 443)”、“http://example.net (隐含端口 80)”、“http://example.com:8080”。请注意,这个 origin 不能保证是该窗口的当前或未来 origin,因为 postMessage 被调用后可能被导航到不同的位置。
- source: 对发送消息的窗口对象的引用; 您可以使用此来在具有不同 origin 的两个窗口之间建立双向通信。
- 发送消息
特别注意
-
如果您不希望从其他网站接收 message,请不要为 message 事件添加任何事件侦听器。 这是一个完全万无一失的方式来避免安全问题。
-
如果您确实希望从其他网站接收 message,请始终使用 origin 和 source 属性验证发件人的身份。任何窗口(包括例如 http://evil.example.com)都可以向任何其他窗口发送消息,并且您不能保证未知发件人不会发送恶意消息。但是,验证身份后,您仍然应该始终验证接收到的消息的语法。否则,您信任只发送受信任邮件的网站中的安全漏洞可能会在您的网站中打开跨网站脚本漏洞。
-
当您使用 postMessage 将数据发送到其他窗口时,始终指定精确的目标 origin,而不是 *。 恶意网站可以在您不知情的情况下更改窗口的位置,因此它可以拦截使用 postMessage 发送的数据。