使用 postMessage + iframe 实现跨域通信

一、postMessage

window.postMessage() 方法可以安全地实现跨源通信。通常,对于两个不同页面的脚本,只有当执行它们的页面位于具有相同的协议(通常为https),端口号(443为https的默认值),以及主机(两个页面的模数 Document.domain设置为相同的值)时,这两个脚本才能相互通信。window.postMessage() 方法提供了一种受控机制来规避此限制,只要正确的使用,这种方法就很安全。

调用 postMessage() 方法时,向目标窗口派发一个 Event 消息。 该 Event 消息的 data 属性为 postMessage() 的数据;origin 属性表示调用 postMessage() 方法的页面的地址。

二、语法

otherWindow.postMessage(message, targetOrigin)

说明

  • otherWindow:其他窗口的一个引用,比如 iframe 的 contentWindow 属性、执行 window.open 返回的窗口对象、或者是命名过或数值索引的 window.frames。
  • message:将要发送到其他 window 的数据。它将会被结构化克隆算法序列化。这意味着你可以不受什么限制的将数据对象安全的传送给目标窗口而无需自己序列化。
  • targetOrigin:通过窗口的 origin 属性来指定哪些窗口能接收到消息事件,其值可以是字符串 * (表示无限制)或者一个 URI。在发送消息的时候,如果目标窗口的协议、主机地址或端口这三者的任意一项不匹配 targetOrigin 提供的值,那么消息就不会被发送;只有三者完全匹配,消息才会被发送。

三、示例

我配了两个域名 example.mazey.cnexample0.mazey.cn,其中 http://example0.mazey.cn/post-message/send.html 会给 http://example.mazey.cn/post-message/receive.html 发送一条消息 Message From Mazey.

send.html

<script>
  window.onload = function () {
    window.parent.postMessage(
      'Message From Mazey.',
      '*'
    )
  }
</script>

receive.html

<script>
  // 监听
  window.addEventListener(
    'message',
    event => {
      let origin = event.origin || event.originalEvent.origin
      console.log(event, origin, event.data) // MessageEvent{...} "http://example0.mazey.cn" "Message From Mazey."
    }
  )
  // 使用 JS 加载 iframe,保证监听创建后再加载 iframe。
  let iframeEle = document.createElement('iframe')
  iframeEle.src = 'http://example0.mazey.cn/post-message/send.html'
  iframeEle.style = 'border: none;width: 0;height: 0;'
  document.body.insertBefore(iframeEle, document.body.firstChild)
</script>

注意

如果发送的消息有敏感信息(例如:密码),始终验证接受时的 event.origin 和指定发送时的 targetOrigin。

发表评论

电子邮件地址不会被公开。 必填项已用*标注