多域名/端口数据同步方案咨询 基于socket.io的跨域聊天实时同步问题
跨域名Socket.io实时聊天方案实现
核心逻辑
Socket.io原生支持跨域通信,你需要解决的核心问题是会话身份绑定、跨域合法性校验、消息定向路由,而非单纯的网络连通问题。
具体实现步骤
1. 服务端Socket.io开启跨域配置
Node端的Socket.io服务优先完成跨域规则配置,支持动态校验域名合法性,生产环境不要直接使用通配符:
const { Server } = require("socket.io"); const io = new Server(3000, { cors: { // 动态校验域名,需支持任意域名接入时可直接放行,后续在业务层做签名校验 origin: (origin, callback) => callback(null, true), credentials: true }, // 默认开启,WebSocket连接失败自动降级为HTTP长轮询,适配严格跨域限制的浏览器环境 transports: ["websocket", "polling"] });
2. 嵌入端(第三方域名聊天组件)会话初始化
每个嵌入到第三方站点的聊天组件初始化时,生成唯一访客标识,和分配给接入站点的唯一appKey绑定,上报到服务端完成会话关联:
import { io } from "socket.io-client"; // 访客ID存在本地存储,支持页面刷新后续会 const visitorId = localStorage.getItem('chat_visitor_id') || Math.random().toString(36).slice(2, 12); localStorage.setItem('chat_visitor_id', visitorId); const socket = io("你的主域名Socket服务地址", { query: { appKey: "提前分配给接入站点的唯一标识", userType: "visitor", visitorId: visitorId }, withCredentials: true }); // 访客发送消息事件 const sendMsg = (content) => { socket.emit("visitor_send_msg", { content, timestamp: Date.now() }); }; // 监听坐席回复消息 socket.on("receive_agent_msg", (data) => { console.log("收到坐席消息:", data.content); });
3. 服务端会话绑定与消息路由
服务端维护会话映射关系,同时用房间机制对坐席做分组,实现消息定向推送:
// 生产环境用Redis存储,支持多实例部署、分布式会话共享 const sessionMap = new Map(); io.on("connection", (socket) => { const { appKey, visitorId, userType, agentId } = socket.handshake.query; // 访客接入逻辑 if (userType === "visitor") { const sessionId = `${appKey}_${visitorId}`; // 绑定会话ID与Socket实例ID sessionMap.set(sessionId, socket.id); // 通知对应商户的所有坐席有新访客接入 io.to(`merchant_${appKey}_agent_room`).emit("new_visitor", { sessionId, visitorId }); // 转发访客消息到对应坐席房间 socket.on("visitor_send_msg", (data) => { io.to(`merchant_${appKey}_agent_room`).emit("receive_visitor_msg", { sessionId, content: data.content, timestamp: data.timestamp }); }); } // 坐席接入逻辑 if (userType === "agent") { // 坐席加入所属商户的专属房间,接收该商户下所有访客消息 socket.join(`merchant_${appKey}_agent_room`); // 转发坐席回复到对应访客窗口 socket.on("agent_send_msg", (data) => { const targetSocketId = sessionMap.get(data.sessionId); if (targetSocketId) { io.to(targetSocketId).emit("receive_agent_msg", { content: data.content, timestamp: data.timestamp }); } }); } });
4. 主域名坐席端接入
坐席登录后携带身份标识接入Socket服务,加入对应商户房间即可接收消息:
import { io } from "socket.io-client"; const socket = io("你的主域名Socket服务地址", { query: { userType: "agent", appKey: "当前坐席所属商户的appKey", agentId: "坐席账号唯一ID" } }); // 监听新访客接入 socket.on("new_visitor", (data) => { console.log("新访客接入:", data.sessionId); }); // 监听访客发送的消息 socket.on("receive_visitor_msg", (data) => { console.log("收到访客消息:", data.content); }); // 坐席发送回复 const sendReply = (sessionId, content) => { socket.emit("agent_send_msg", { sessionId, content, timestamp: Date.now() }); };
生产环境优化建议
- 会话映射、房间关系改用Redis存储,支持Socket服务多实例扩容,避免单点故障
- 所有消息先写入数据库再推送,防止消息丢失,支持历史消息回溯
- 增加接入签名校验,嵌入端初始化时携带
appKey+时间戳+签名,服务端校验合法性,拦截恶意接入
内容的提问来源于stack exchange,提问作者karthick
相关产品推荐
相关产品推荐

