解决postMessage在IE11跨域无法通信问题

1,792 阅读2分钟

曾经遇过一个case,公司原有的一套系统需要和新系统做交互,流程是从旧系统打开新窗口加载新系统,然后在新系统触发某些操作时,发送信息回旧系统并处理。HTML5有一个postMessage的API可以支持跨窗口通信。参考MDN做了一个简单的POC

// 旧系统 http://www.a.com
const win = window.open('http://www.b.com')
win.postMessage('Hello from a.', 'http://www.b.com');

function receiveMessage (event) {
  if (event.origin !== "http://www.b.com") {
    return;
  }

  // event.source是我们通过window.open打开的弹出页面win
  // event.data是win发送给当前页面的消息'Hello from b.'
}

window.addEventListener('message', receiveMessage, false);

// 新系统 http://www.b.com
function receiveMessage (event) {
  if (event.origin !== 'http://www.a.com') {
    return;
  }

  // event.source就当前弹出页的来源页面(http://www.a.com)
  // event.data是'Hello from a.'

  event.source.postMessage('Hello from b.', event.origin);
}

window.addEventListener('message', receiveMessage, false);

这个方法可以实现窗口间双向通信。但旧系统和新系统存在以下两个问题:

  1. 需要支持IE11
  2. 旧系统与新系统跨域

我拿了个旧系统的测试环境做了几轮测试。发现这个postMessage的API在IE且跨域时并不能很好的工作,会出现通信失败的情况。毫无头绪之下,只好到Stack Overflow逛逛,试了多种方法还是无法成功解决IE这个“神奇”浏览器的兼容性问题。最后在一个评论中发现如下方法,测试后意外发现解决了我的问题。

// 把原来的代码
const win = window.open('http://www.b.com')
// 改为
const win = window.open('/')
win.location.href = 'http://www.b.com'

原因猜测:直接使用新系统域名创建窗口,由于生成的新窗口和旧窗口跨域,所以引用不成功,所以postMessage无法正常使用postMessage。使用第二种方法,先使用当前域名的根路由创建窗口,这时新窗口和旧窗口是同域的,再使用api把新窗口地址跳转到新平台,这时候由于引用已存在,所以可以正常双向通信。