前端实现两个网站页面跨域通信

问题描述:
A、B两个网站要实现跨域通信,可通过postMessage来实现。

A网站地址:A_HOST
B网站地址:B_HOST

  1. A系统页面发送数据给B系统页面:调用B页面window对象的postMessage方法
//在A系统页面添加以下代码
let bIframeWin = null
 layer.open({
            type: 2,
            title:"B系统页面",
            area: ['96%', '96%'],
            content:B_HOST+"/pageB.html",
            success:function (layero, index) {
            //获取B页面window,用于后面向B页面传递信息
                bIframeWin = window[layero.find('iframe')[0]['name']];
            }
        });
//或通过window.open打开
//bIframeWin = window.open(B_HOST+"/pageB.html")
window.addEventListener('message', function(e){
    let act = e.data.act
    if (act == 'beReady') {
    //接收到B页面传来准备好了的消息,确保B页面已加载完再给它传递数据
       let data = {
            act: 'setInfo',
            params:params //一些你要传的参数
        };
        bIframeWin.postMessage(data, B_HOST); //发送数据给B页面(来自另一个跨域系统)
    }
}, false);
  1. B系统页面监听消息:判断是不是指定的地址,是则接收信息,并调用A系统页面window.parent.postMessage回复父页面
//向打开B页面的opener发送消息,告诉它可以开始传递数据了
 window.opener && window.opener.postMessage({
            act: 'beReady'
        },A_HOST)
 window.addEventListener("message", function(event){ 
        if (event.origin !== A_HOST) 
        return; 
        if(event.data.act == "setInfo"){
            let params = event.data.params
            sessionStorage.setItem("token",JSON.stringify(params.token))
            //获取A系统页面的window->window.parent
             window.parent.postMessage({
                act: 'response',
                msg: {
                    answer: '我接收到啦!'
                }
            }, A_HOST);//'*' 不限制域
        }
}, false); 
<think> 我们正在讨论前端两个页签(即浏览器中的两个标签页)之间的通信方式。根据引用内容,我们可以总结出几种常见的方法: 1. **WebSocket**:这是一种独立的协议,可以在服务器和客户端之间建立实时双向通信(引用[2])。两个页签都可以连接到同一个WebSocket服务器,通过服务器中转消息来实现通信。这种方式适用于任何同源或不同源的页面,但需要服务器支持。 2. **长轮询(Long-Polling)或Comet技术**:引用[3]提到Comet技术,包括长轮询和长连接。这种方式实际上是通过服务器中转消息,两个页签都通过不断请求或保持长连接来与服务器通信,然后服务器将消息推送给另一个页签。这种方式也可以实现标签页通信,但同样需要服务器支持。 3. **使用BroadcastChannel API**:引用[4]中提到了使用`BroadcastChannel`,这是现代浏览器提供的API,允许同源的不同浏览器上下文(如标签页、iframe等)之间进行通信。我们只需要创建一个相同名称的频道,两个标签页就可以通过该频道互相发送和接收消息。 4. **使用SharedWorker**:SharedWorker是Web Worker的一种,可以被多个浏览器上下文(如多个标签页)共享。我们可以通过SharedWorker作为中介来实现标签页之间的通信。 5. **使用localStorage或sessionStorage**:当同源的两个标签页中的一个修改了localStorage或sessionStorage时,另一个标签页可以通过监听`storage`事件来捕获变化。这种方式简单,但只能传递字符串数据,且受同源策略限制。 6. **使用window.postMessage和iframe作为桥梁**:引用[4]中描述了一种通过嵌入一个同源的iframe作为桥梁,来实现页面通信的方法。但如果是同源的两个标签页,我们可以直接使用`window.postMessage`,不过需要注意获取到另一个标签页的window对象的引用(例如通过`window.open`或`window.opener`)。 7. **使用IndexedDB**:类似于localStorage,但可以存储更复杂的数据结构。我们可以通过轮询或监听IndexedDB的变化来实现通信,但通常不如其他方法实时。 8. **使用Service Worker**:Service Worker可以拦截和处理网络请求,并且可以向多个标签页发送消息(通过`postMessage`)。我们可以利用Service Worker作为消息中心,实现标签页之间的通信。 考虑到用户的问题是实现两个页签通信,我们主要关注不需要服务器的纯前端方案。在同源的情况下,推荐使用以下方法: - **BroadcastChannel API**:最简单直接,专门用于同源上下文之间的通信。 - **localStorage的storage事件**:简单易用,兼容性较好。 - **SharedWorker**:适用于需要复杂逻辑或长时间通信的场景。 - **Service Worker**:如果应用已经是PWA,使用Service Worker可以同时处理离线消息。 对于不同源的标签页,由于浏览器安全限制,纯前端方法很难直接通信,通常需要借助服务器(如WebSocket)或者使用一个同源的iframe桥(如引用[4]所述)来中转消息。 下面我们分别给出BroadcastChannel和localStorage两种方式的示例代码: ### BroadcastChannel方式 ```javascript // 在标签页1和标签页2中执行相同的代码 const channel = new BroadcastChannel('tab-communication'); // 发送消息 channel.postMessage({ type: 'message', data: 'Hello from Tab1' }); // 接收消息 channel.onmessage = (event) => { console.log('Received message:', event.data); }; ``` ### localStorage方式 ```javascript // 标签页1发送消息 localStorage.setItem('tab-msg', JSON.stringify({ from: 'Tab1', data: 'Hello' })); // 标签页2监听storage事件 window.addEventListener('storage', (event) => { if (event.key === 'tab-msg') { const message = JSON.parse(event.newValue); console.log('Received message:', message); // 处理完后可以清除,以免重复处理 localStorage.removeItem('tab-msg'); } }); ``` 注意:storage事件只在同一个名下的不同标签页之间触发,且发送消息的标签页自身不会触发storage事件。 §§相关问题§§ 1. BroadcastChannel API的浏览器兼容性如何? 2. 如何实现标签页通信? 3. 使用localStorage进行标签页通信有什么限制? 4. Service Worker如何用于标签页通信? 5. 如何实现多个标签页之间的实时同步? </think> 以下是实现前端两个浏览器标签页(页签)通信的主要方式及其详细说明: ### 一、同源标签页通信方式 1. **Broadcast Channel API** 现代浏览器原生支持的专用通信通道: ```javascript // 页签A/B 创建同名的频道 const channel = new BroadcastChannel('tab_channel'); // 发送消息 channel.postMessage({ type: 'update', data: 'Hello Tab!' }); // 接收消息 channel.onmessage = (e) => { console.log('Received:', e.data); } ``` **特点**:专门为标签通信设计,无需借助服务器或DOM操作。 2. **LocalStorage/SessionStorage 事件** 利用存储事件监听变化: ```javascript // 页签A 发送消息 localStorage.setItem('tab_msg', JSON.stringify({ data: 'Hello' })); // 页签B 监听变化 window.addEventListener('storage', (e) => { if (e.key === 'tab_msg') { console.log('Received:', JSON.parse(e.newValue)); } }); ``` **注意**:发送消息的页签自身不会触发该事件。 3. **SharedWorker 通信** 通过共享Worker中转消息: ```javascript // 共享Worker (shared-worker.js) onconnect = (e) => { const port = e.ports[0]; port.onmessage = (event) => { // 广播给所有连接的页签 self.clients.matchAll().then(clients => { clients.forEach(client => client.postMessage(event.data)); }); }; }; // 页签A/B 连接Worker const worker = new SharedWorker('shared-worker.js'); worker.port.postMessage('Message from Tab'); worker.port.onmessage = (e) => console.log(e.data); ``` ### 二、标签页通信方式 4. **Window.postMessage + iframe桥接** 引用[4]中描述的方案: ```javascript // 在双方页签嵌入同源iframe桥 <iframe id="bridge" src="https://bridge-domain.com"></iframe> // 页签A 通过iframe发送消息 document.getElementById('bridge').contentWindow.postMessage( { type: 'bridge-msg', data: 'Hello' }, '*' ); // iframe桥接收后广播给其他页签 window.addEventListener('message', (e) => { if (e.data.type === 'bridge-msg') { // 转发到其他页签(通过BroadcastChannel等) } }); ``` **核心**:利用同源iframe作为消息中转站。 5. **WebSocket 服务器中转** 引用[2]提到的双向通信方案: ```javascript // 两个页签连接到同一个WebSocket服务器 const socket = new WebSocket('wss://server.com'); // 页签A 发送消息 socket.send(JSON.stringify({ to: 'tabB', data: 'Hi' })); // 页签B 接收消息 socket.onmessage = (e) => { const msg = JSON.parse(e.data); if (msg.to === 'tabB') console.log(msg.data); }; ``` **特点**:适用于复杂场景,但需服务器支持[^2]。 ### 三、传统通信方案(兼容旧浏览器) 6. **定时轮询(Polling)** 通过定时检查服务器数据变化实现同步: ```javascript setInterval(() => { fetch('/api/check-messages').then(res => res.json()) .then(messages => { /* 处理消息 */ }); }, 1000); ``` 7. **长轮询(Long-Polling)** 引用[3]描述的Comet技术: 客户端发起请求后服务器保持连接,直到有新消息才响应[^3]。 --- ### 方案对比 | 方式 | 同源支持 | 支持 | 实时性 | 复杂度 | |---------------------|----------|----------|----------|--------| | BroadcastChannel | ✅ | ❌ | 即时 | ⭐ | | localStorage事件 | ✅ | ❌ | 高 | ⭐⭐ | | SharedWorker | ✅ | ❌ | 即时 | ⭐⭐⭐ | | iframe桥接 | ✅ | ✅ | 即时 | ⭐⭐⭐⭐ | | WebSocket | ✅ | ✅ | 即时 | ⭐⭐⭐⭐ | | 轮询 | ✅ | ✅ | 低 | ⭐⭐ | > **选择建议**: > - 同源场景优先选 **BroadcastChannel**(简单高效) > - 场景用 **iframe桥接** 或 **WebSocket** > - 需兼容旧浏览器时使用 **localStorage事件** 或 **轮询**
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值