使用 WebSocket 实现跨域 iframe 通信

发布于:2024-04-25 ⋅ 阅读:(16) ⋅ 点赞:(0)

宫崎骏风-罗罗诺亚·索隆

前言

本文是使用 WebSocket 实现跨域 iframe 通信思路实现了一个本地 Demo,功能有:

  • iframe 页面之间互相通信
  • 嵌套的 iframe 通信
  • WebSocket 客户端与服务端通信

Demo预览效果

由于完整流程操作录制的Gif图片为306M,上传图片发现掘金有限制,图片体积不能超过20M,静态图附上

页面布局

整体运行效果都是在本地运行的,启动了3个前端服务页面,分别是 8090,8091,8092

屏幕主页面是8090服务运行的,有两个卡片区可以向其他两个页面进行通信

页面中使用iframe嵌入了8091和8092的页面,分别是这两个卡片区,嵌入的卡片页也可以分别向其他两个页面进行数据通信

代码思路实现

目录结构

这是本地Demo的目录结构,每个服务都根据端口名进行目录区分,如果看GitHub上的源码,记得先看一下README.md文件

主页面

主页面是一个HTML单页,这里使用 http-server -p 8090 命令运行起来

HTML页面中使用button按钮点击分别向8091发送数据,分别使用div接收对应页面发送的数据

<div style="display:flex;">
    <div class="card" style="height:120px;">
        <input type="text" id="inputData" placeholder="输入数据">
        <button id="sendButton1">向页面8091发送数据</button>
        <br />
        <div>
            接收8091的数据:<div id="response1"></div>
        </div>
    </div>
    <br />
    <div class="card" style="height:120px;">
        <input type="text" id="inputData2" placeholder="输入数据">
        <button id="sendButton2">向页面8092发送数据</button>

        <div>
            接收8092的数据:<div id="response2"></div>
        </div>
    </div>
</div>
<div style="display:flex;">
    <div class="card">
        <iframe id="iframe1" src="http://localhost:8091"></iframe>
    </div>
    <div class="card">
        <iframe id="iframe2" src="http://localhost:8092"></iframe>
    </div>
</div>

在页面初始化后进行 WebSocket 进行连接,然后使用 onmessage 监听服务端发送过来的消息

注意!

这里初始化的连接地址是 ws://localhost:9000,9000端口是WebSocket服务端,使用node运行起来的

使用 ws.send() 向其他页面发送JSON字符串消息,sender 表示当前发送者,如:8090,receiver 表示接收者,如:8091,msg 为发送和接收的数据内容

const ws = new WebSocket('ws://localhost:9000');

ws.onopen = function () {
    console.log('8090页面 与 9000 WebSocket连接成功')
};

ws.onmessage = function (event) {
    console.log('8090 onmessage: ', event.data)
    if (event.data) {
        let objData = JSON.parse(event.data)
        if (objData.receiver === 8090) {
            if (objData.sender === 8091) {
                document.getElementById('response1').innerHTML = objData.msg;
            }

            if (objData.sender === 8092) {
                document.getElementById('response2').innerHTML = objData.msg;
            }
        }
    }

};

// 向8091页面发送数据
document.getElementById('sendButton1').onclick = function () {
    const data = document.getElementById('inputData').value;
    console.log('data1: ', data)

    ws.send(JSON.stringify({
        sender: 8090,
        msg: data,
        receiver: 8091
    }));
};


// 向8092页面发送数据
document.getElementById('sendButton2').onclick = function () {
    const data = document.getElementById('inputData2').value;
    console.log('data1: ', data)

    ws.send(JSON.stringify({
        sender: 8090,
        msg: data,
        receiver: 8092
    }));
};


iframe子页面

子页面有两个HTML页,分别使用 http-server -p 8091http-server -p 8092 命令运行的,这两个页面发送数据和8090主页面实现一样,这里就不做多的介绍了,区别点在接收数据这里,接收数据使用一个 <div id="response"></div> 进行的接收数据展示,然后根据 sender 的来源提示不同的文字

ws.onmessage = function (evt) {
    console.log('8091 message ', evt)
    const received_msg = evt.data;
    console.log("接收到的数据: " + received_msg);

    let objData = JSON.parse(received_msg)
    console.log('objData: ', objData)

    if (objData.receiver === 8091) {
        if (objData.sender === 8090) {
            document.getElementById('response').innerHTML = "来自8090的消息: " + objData.msg;
        }

        if (objData.sender === 8092) {
            document.getElementById('response').innerHTML = "来自8092的消息: " + objData.msg;
        }
    }
};

WebSocket 服务端

服务端使用node运行,端口9000,引用了ws包,服务端的逻辑很简单,只提供一个socket服务,然后给所有客户端进行消息转发


let WebSocketServer = require('ws').Server;
let wss = new WebSocketServer({ port: 9000 });

let clients = [];

wss.on('connection', (ws) => {
    console.log(ws)
    clients.push(ws);

    ws.on('message', (message) => {
        console.log('received: %s', message);
        // 在这里处理接收到的消息

        // 注意!!!
        // 这里面的数据要使用 toString() 转成字符串
        // 否则客户端接收的是个 blob 对象,将无法正确解析数据
        console.log(message.toString())

        broadcast(message.toString())
    });


});

function broadcast(message) {
    clients.forEach(function (client) {
        client.send(message);
    });
}

clients 变量记录所有客户端,在接收到消息后直接转发

注意!

message.toString() 服务端的消息需使用 toString() 转成字符串,否则客户端接收的是个 blob 对象,将无法正确解析数据

http-server

使用 http-server 可以快速搭建一个简单的服务器,如果本地有 node 环境的话,执行 npm i http-server -g 全局安装即可

http-server 其他服务端程序也有类似的库,自行按需安装

完整代码地址

欢迎大家讨论交流,如果喜欢本文章或感觉文章有用,动动你那发财的小手点赞、收藏、关注再走呗 ^_^ 

微信公众号:草帽Lufei