浏览器跨页面通讯
文章目录
同源策略是一个重要的安全策略,它用于限制一个origin的文档或者它加载的脚本如何能与另一个源的资源进行交互。它能帮助阻隔恶意文档,减少可能被攻击的媒介。
**同源定义: ** 两个页面的Protocol(协议)、Port(端口)、host(域名)相同
例如:http://www.aaa.com/dir/page.html
协议: ** http://
, 端口: 80(默认)
,域名:** www.aaa.com
。
1 | "http://www.aaa.com/dir/other.html" :同源 |
同源策略下的跨页面通讯
Broadcast Channel API
Broadcast Channel API 可以实现同 源 下浏览器不同窗口,Tab页,frame或者 iframe 下的 浏览器上下文 (通常是同一个网站下不同的页面)之间的简单通讯。
Note: 此特性在 Web Worker 中可用。
广播频道会被命名和绑定到指定的源。
通过创建一个监听某个频道下的 BroadcastChannel
对象,你可以接收发送给该频道的所有消息。一个有意思的点是,你不需要再维护需要通信的 iframe 或 worker 的索引。它们可以通过构造 BroadcastChannel
来简单地“订阅”特定频道,并在它们之间进行全双工(双向)通信。
例子🌰
1 | // 连接到广播频道 |
- BroadcastChannel() - 构建函数用于创建一个
BroadcastChannel
对象,并与对应的频道相关联。 - BroadcastChannel.onmessage - 当
BroadcastChannel
接收到类型为MessageEvent
的message
事件时,**BroadcastChannel.onmessage**
属性可以指定一个函数,作为该事件对应的事件处理程序来执行。 - BroadcastChannel.postMessage() - 可以使用
BroadcastChannel.postMessage()
发送一条任意Object
类型的消息,给所有同源下监听了该频道的所有浏览器上下文。消息以message
事件的形式发送给每一个绑定到该频道的广播频道。 - BroadcastChannel.close() - 通过调用
BroadcastChannel.close()
方法,可以马上断开其与对应频道的关联,并让其被垃圾回收。这是必要的步骤,因为浏览器没有其它方式知道频道不再被需要。
SharedWorker
SharedWorker
接口代表一种特定类型的 worker,可以从几个浏览上下文中访问,例如几个窗口、iframe 或其他 worker。SharedWorker 被多个页面实例化时, 数据是共享的.
例子🌰
1 | // page 1 |
contentWindow
contentWindow
属性返回当前HTMLIFrameElement的Window对象. 你可以使用这个Window
对象去访问这个iframe的文档和它内部的DOM. 这个是可读属性, 但是它的属性像全局Window
一样是可以操作的.
1 | var x = document.getElementsByTagName("iframe")[0].contentWindow; |
Web Storage API
Web Storage API 提供了存储机制,通过该机制,浏览器可以安全地存储键值对.
Web Storage 包含如下两种机制:
sessionStorage
为每一个给定的源(given origin)维持一个独立的存储区域,该存储区域在页面会话期间可用(即只要浏览器处于打开状态,包括页面重新加载和恢复)。localStorage
同样的功能,但是在浏览器关闭,然后重新打开后数据仍然存在。
这两种机制是通过 Window.sessionStorage
和 Window.localStorage
属性使用(更确切的说,在支持的浏览器中 Window
对象实现了 WindowLocalStorage
和 WindowSessionStorage
对象并挂在其 localStorage
和 sessionStorage
属性下)—— 调用其中任一对象会创建 Storage
对象,通过 Storage
对象,可以设置、获取和移除数据项。对于每个源(origin)sessionStorage
和 localStorage
使用不同的 Storage 对象——独立运行和控制。
通过 Web Storage中的通过 StorageEvent 响应存储的变化 ,可以做到同源下的跨页面的数据同步。
1 | window.addEventListener('storage', function (e) { |
无论何时,Storage
对象发生变化时(即创建/更新/删除数据项时,重复设置相同的键值不会触发该事件,Storage.clear()
方法至多触发一次该事件),StorageEvent
事件会触发。在同一个页面内发生的改变不会起作用——在相同域名下的其他页面(如一个新标签或 iframe)发生的改变才会起作用。在其他域名下的页面不能访问相同的 Storage 对象。
跨源通讯
postMessage
window.postMessage()
方法可以安全地实现跨源通信。对于两个不同页面的脚本,一般情况下需要满足同源策略才能进行数据通讯。但window.postMessage()
方法提供了一种受控机制来规避此限制,只要正确的使用,这种方法就很安全。
从广义上讲,一个窗口可以获得对另一个窗口的引用(比如 targetWindow = window.opener
),然后在窗口上调用 targetWindow.postMessage()
方法分发一个 MessageEvent
消息。接收消息的窗口可以根据需要自由处理此事件。传递给 window.postMessage() 的参数(比如 message )将通过消息事件对象暴露给接收消息的窗口。
1 | otherWindow.postMessage(message, targetOrigin, [transfer]); |
otherWindow - 其他窗口的一个引用,比如iframe的contentWindow属性、执行window.open返回的窗口对象、或者是命名过或数值索引的window.frames。
message - 将要发送到其他 window的数据。它将会被结构化克隆算法序列化。这意味着你可以不受什么限制的将数据对象安全的传送给目标窗口而无需自己序列化。[1]
targetOrigin - 通过窗口的origin属性来指定哪些窗口能接收到消息事件,其值可以是字符串”“(表示无限制)或者一个URI。在发送消息的时候,如果目标窗口的协议、主机地址或端口这三者的任意一项不匹配targetOrigin提供的值,那么消息就不会被发送;只有三者完全匹配,消息才会被发送。这个机制用来控制消息可以发送到哪些窗口;例如,当用postMessage传送密码时,这个参数就显得尤为重要,必须保证它的值与这条包含密码的信息的预期接受者的origin属性完全一致,来防止密码被恶意的第三方截获。*如果你明确的知道消息应该发送到哪个窗口,那么请始终提供一个有确切值的targetOrigin,而不是*。不提供确切的目标将导致数据泄露到任何对数据感兴趣的恶意站点。
例子🌰
1 | /* |
1 | /* |
MessageEvent
1 | window.addEventListener("message", receiveMessage, false) ; |
event对象的打印结果截图如下:
这里重点介绍event对象的四个属性
- data : 指的是从其他窗口发送过来的消息对象;
- type: 指的是发送消息的类型;
- source: 指的是发送消息的窗口对象;
- origin: 指的是发送消息的窗口的源
Refer To
https://www.ruanyifeng.com/blog/2016/04/same-origin-policy.html
作者: Fynn
本文采用知识共享署名-非商业性使用 4.0 国际许可协议进行许可