嵌入跨域站点的iframe与其打开的同域新窗口如何实现通信?
跨域嵌套iframe与同域新窗口通信解决方案
方案1:通过顶层父页做消息中转(兼容性最佳,无浏览器特性依赖)
该方案利用跨源postMessage能力,由顶层页(xyz.com)作为消息中转方,不需要依赖浏览器特殊API,兼容所有现代浏览器。
实现步骤
- 顶层页xyz.com全局注册
message事件监听器,负责转发来自abc.com域名下上下文的消息:
// xyz.com 顶层页代码 window.addEventListener('message', (e) => { // 安全校验:仅处理来自可信域名abc.com的消息 if (e.origin !== 'https://abc.com') return const message = e.data // 接收iframe注册请求,记录目标iframe的引用 if (message.type === 'register_target_iframe') { window._targetAbcIframe = e.source } // 接收新窗口的转发请求,将消息转发给已注册的iframe if (message.type === 'forward_to_iframe') { window._targetAbcIframe?.postMessage(message.payload, 'https://abc.com') } })
- abc.com域名下的iframe加载完成后,先向顶层页发送注册请求,再实现新窗口打开逻辑,同时将顶层页origin作为查询参数传递给新窗口:
// abc.com iframe 代码 // 注册iframe到顶层页 window.parent.postMessage({ type: 'register_target_iframe' }, 'https://xyz.com') // 新窗口打开逻辑 const openNewWindow = () => { const topOrigin = encodeURIComponent('https://xyz.com') window.open(`https://abc.com/new_window?topOrigin=${topOrigin}`, '_blank') } // 监听顶层页转发的新窗口消息 window.addEventListener('message', (e) => { if (e.origin !== 'https://abc.com') return console.log('收到新窗口消息:', e.data) })
- abc.com域名下的新窗口加载完成后,从查询参数获取顶层页origin,向顶层页发送待转发的消息:
// abc.com 新窗口代码 const searchParams = new URLSearchParams(location.search) const topOrigin = searchParams.get('topOrigin') // 发送需要转发给iframe的消息 window.top.postMessage({ type: 'forward_to_iframe', payload: { action: 'data_sync', content: '自定义消息内容' } }, topOrigin)
方案2:使用SharedWorker实现同域通信(无需顶层页配合)
该方案利用SharedWorker同域多上下文共享的特性,直接在abc.com域名下实现iframe和新窗口的点对点通信,不需要顶层页做任何修改。
实现步骤
- 首先在abc.com域名下部署共享worker脚本
shared-mq-worker.js:
// abc.com shared-mq-worker.js 代码 const connectedPorts = [] // 监听新的上下文连接 self.onconnect = (connectEvent) => { const port = connectEvent.ports[0] connectedPorts.push(port) // 监听当前端口的消息,广播给所有其他已连接的端口 port.onmessage = (messageEvent) => { connectedPorts.forEach(targetPort => { if (targetPort !== port) { targetPort.postMessage(messageEvent.data) } }) } }
- abc.com iframe初始化共享worker,监听消息:
// abc.com iframe 代码 const sharedWorker = new SharedWorker('/shared-mq-worker.js') sharedWorker.port.start() sharedWorker.port.onmessage = (e) => { console.log('收到新窗口消息:', e.data) }
- abc.com新窗口初始化同一个共享worker,发送消息:
// abc.com 新窗口代码 const sharedWorker = new SharedWorker('/shared-mq-worker.js') sharedWorker.port.start() // 发送消息 sharedWorker.port.postMessage({ action: 'data_sync', content: '自定义消息内容' })
注意事项
- 该方案不支持IE浏览器,主流现代浏览器(Chrome 4+, Firefox 29+, Safari 16+)均已支持
- 若浏览器禁用了worker,该方案不可用,建议降级使用方案1
补充说明
你遇到的同域localStorage不同步问题,是因为第三方上下文(嵌入在xyz.com下的abc.com iframe)被浏览器的跟踪防护策略隔离了存储,和第一方打开的abc.com新窗口的存储分区相互独立,若要使用localStorage方案需要申请Storage Access API权限,实现复杂度远高于上述两种方案,不推荐使用。
内容的提问来源于stack exchange,提问作者avr_dude
相关产品推荐
相关产品推荐

