前段时间,在重构业务相关SDK对接方案中,涉及到跨域Iframe通信的场景,最终采取的方案是window.postMessage
, 这里总结一下该方案的应用场景及其注意事项。
该API旨在安全的实现跨源通信。通常情况下,两个页面之间的脚本,只有在 协议 主机名 和 端口号 完全相同的情况下,才能互相通信。但是 postMessage
方法却可以实现 跨源调用
,这也是该API设计的核心所在。
另外,该API还实现了一种安全机制,只要正确的使用,就很安全。至于安全机制,我觉得主要体现在如下的几个方面。
首先回顾一下该API的语法设计:
otherWindow.postMessage(message, targetOrigin, [transfer]);
otherWindow
MDN上指出,这是其他窗口的一个引用,比如iframe的contentWindow属性、执行window.open返回的窗口对象、或者是命名过或数值索引的window.frames。
需要注意的是,postMessage是window上的一个的方法,我们在哪个window对象调用该方法,就是往哪个window对象发送消息。也就是说,我们希望向目标window对象发送消息,首先需要获取该window对象对用。当然,如果是在当前window对象下调用该方法,就是在当前window范围内发送消息。
message
需要发送的消息,在发送时,会被「结构化克隆算法」序列化,在接受时,会自动反序列化,也就是说,除了发送简单的字符串格式数据之外,我们还可以发送对象,数组等数据格式。但是需要额外注意的是⚠️:结构化克隆,不支持 Error Function DOM节点等数据格式,所以在传递消息数据时,需要避免上述数据,否则会导致发送失败,例如:
这也是JS语言的安全机制,否则的话,就可以跨域执行脚本了,后果不堪设想啊?
targetOrigin
这个也需要额外注意,在通信时,如果你明确的知道消息应该发送到哪个窗口,那么请始终提供一个有确切值的targetOrigin,而不是*。不提供确切的目标将导致数据泄露到任何对数据感兴趣的恶意站点。
另外,关于监听消息方,会接受到一个MessageEvent消息。一个真实的消息如下:
其中几个需要注意的是:
- source: 发送消息方所处的window对象,这个我们可以用于消息回传。
- target: 接受消息的window对象,就是监听脚本所处的window对象。
- origin: 发送消息方的源