postMessage实现两个页面间的跨域通信

1,257 阅读1分钟

由于web同源策略的限制,当两个页面处于不同的域名,而又需要数据通信时,两页面是无法交互的,这对页面间的信息传递造成了不小的麻烦,经过一系列的尝试,有以下方法可以实现,在此做个记录。

主要实现思路:

A发送信息给B,带有open:true标志,表示B可以接收A传过来的信息;

B接收到信息,发送成功标志给A;

A收到成功标志后,传open:false的标志给B,表示消息通信成功,关闭通信。

代码实现

A页面代码:

const PAGE_DESIGN_URL = 'url' // 域名地址

function onReceiveMessage(design, appMessage){
  // 周期发送消息给B页面
  const sendMessage = setInterval(() => {
    var message = JSON.stringify(appMessage);
    design.postMessage(message, PAGE_DESIGN_URL);
  }, 1000)

  // 接收B页面回调
  function receiveMessage(event) {
    console.log('接收回调', event.origin , BASE_API)
    // BASE_API 为项目域名
    //.PAGE_DESIGN_ORIGIN 为B页面的域名
    // 判断消息是否来自B页面的域名
    if(event.origin !== PAGE_DESIGN_ORIGIN) return
    if(event.data){
      const message = JSON.parse(event.data)
      // 如果成功接收消息,并且返回为200代表页面设计器已接收到消息传送
      if(message.statusCode === 200){
          // 向B页面发送关闭消息传送标志open:false
        design.postMessage(JSON.stringify({open: false}), PAGE_DESIGN_URL);
        // 清空定时发送
        window.clearInterval(sendMessage)
      }
    }
  }
  window.addEventListener("message", receiveMessage, false)
}

const design = window.open(`${PAGE_DESIGN_URL}`, '_blank');
const appMessage = {
    open: true, // 打开连接
    token: '',
    id: '',
    ... // 需要传给B页面的信息
}
onReceiveMessage(design, appMessage)

B页面代码:


function receiveMessage(event) {
    const messageSoure = [
     ... // 域名白名单,只接收指定域名传过来的数据
    ]
   
    if(!messageSoure.includes(event.origin)) {
      console.log(`该域名${event.origin}不在白名单中,请查看:`, messageSoure)  
      return
    }
    
    if(event.data && (typeof event.data) === 'string'){
      // 返回接收信息
      event.source.postMessage(
        JSON.stringify({
          statusCode: 200,
          message: "信息接收成功!"
        }),
      event.origin);

      const appMessageInfo = JSON.parse(event.data)
      // 打开连接时,刷新页面
      if(appMessageInfo.open){ 
        console.log('appMessageInfo', appMessageInfo)
        const {token, id, ...} = appMessageInfo
        if(id === undefined) return
        // 成功时需要执行的代码        
      }else{
        // 关闭事件监听
        window.removeEventListener("message", receiveMessage, false)
      }         
    }
  }
  // 事件监听
  if(isAcceptMessage !== undefined && !isAcceptMessage){
    window.addEventListener("message", receiveMessage, false)
  }