postMessage跨域问题Failed to execute 'postMessage' on 'DOMWindow'解决

10,106 阅读2分钟

最近有个需求场景需要实现iframe页面嵌套并进行web页面和嵌套的iframe之间进行跨域通信。经过调研发现使用postMessage可以解决这个问题。但当我使用postMessage的时候就发生了报错:

Failed to execute 'postMessage' on 'DOMWindow'

网上一般就说这是因为iframe没有加载出来的原因,但是我用setInterval来做定时发送,还是会报错,看来并不是因为iframe没有加载出来导致的。

原因出在哪里呢,最后发现是自己对于官方文档理解不到位导致的。

image.png

postMessage应该是otherWindow,也就是具体的iframe的window,而不是父的window。要向哪个iframe发送数据,就要用哪个iframe所对应的window。如果写成

window.postMessage()

这里的window是父的window,就会报Failed to execute 'postMessage' on 'DOMWindow'的错误,因为DOMWindow并不是某一个具体的iframe,没有办法执行postMessage发送数据。

下面举例来说明一下,假如你的网站里面想嵌套一个B站作为iframe。如果我们网站想给B站iframe发送数据该怎么做。首先在HTML里面写入一个iframe

<iframe src="https://www.bilibili.com/" width={1400} height={700} onLoad={this.iFrameLoadTest}></iframe>

然后在方法里面写:

  iFrameLoadTest = () => {
    const BFrame = window.frames[0]
    BFrame.postMessage('一个测试信息', "https://www.bilibili.com/")
  }

然后就可以在B站里添加一个message的addEventListener用于接收消息了。

window.addEventListener('message', function(e) {
   alert(e.data)
})

如果要反过来,iframe要给父的web页面发消息该怎么写呢?

这时候发送地址就不应该再是BFrame了,而是window.top或者window.parent,因为iframe要给web的父页面发送信息,所以接收方应该是top或者parent,如果还是用的window的话,会接收失败,也报Failed to execute 'postMessage' on 'DOMWindow'这样的错误。

另外,网上有人说,上述错误是因为使用http协议的原因,只有使用https协议才不会报错,经过我验证,使用http协议也不会报错。报错的原因就是因为没有很好的理解otherWindow导致的。

参考资料

[1] window.postMessage MDN

[2] 用postMesage实现跨域,并解决Failed to execute 'postMessage' on 'DOMWindow'