Socket.IO v3.03多用户同时刷新时emit推送数据串户问题求助
问题根因与修复方案
核心问题定位
你遇到的串数据问题核心来自两个高频场景:
- 服务端
userid作用域错误:你打印映射日志的逻辑在await getTickets之前,此时userid是正确的,但如果userid被定义为全局/外层作用域变量,await等待数据库查询的过程中,另一个用户的连接请求会覆盖userid的值,等查询返回执行emit时,拿到的已经是后连接用户的userid,自然会推错对象。 - 客户端多Socket实例残留:你开启了
forceNew: true每次刷新都会生成新的Socket实例,旧实例没有断开和移除监听,会额外接收其他连接的推送消息。
服务端修复方案
将userid改为连接回调内的局部变量,优先用当前Socket实例推送数据,避免全局查找的串发风险,同时增加断开连接的映射清理逻辑:
io.on('connection', async (socket) => { // 从当前连接的query中取token,解析逻辑放在回调内部,userid为局部变量不会被其他连接覆盖 const token = socket.handshake.query['x-token']; const userid = await parseToken(token); if (!userid) { socket.disconnect(); return; } // 更新全局映射 mapSessions[userid] = socket.id; // 直接用当前socket实例推送,完全规避全局查询id的错误风险 socket.emit('ticketList', await getTickets(userid)); // 断开时清理无效映射 socket.on('disconnect', () => { if (mapSessions[userid] === socket.id) { delete mapSessions[userid]; } }) })
客户端修复方案
创建新连接前先断开旧连接、移除旧事件监听,避免多实例同时接收消息:
const connectSocket = useCallback(() => { if (token) { // 清理旧连接 if (window.existSocket) { window.existSocket.disconnect(); window.existSocket.off('ticketList'); } const socketTemp = io.connect(serverPath, { transports: ['websocket'], autoConnect: true, reconnection:true, forceNew: true, query: { 'x-token': token } }); window.existSocket = socketTemp; dispatch(setSocket(socketTemp)); // 事件绑定在当前新实例上 socketTemp.on('ticketList', (data) => { // 建议加一层兜底校验:返回数据的用户标识和本地登录用户id不一致就丢弃 if (data.userid === localUserid) { // 处理待办数据逻辑 } }) } }, [token, serverPath, dispatch]);
额外优化建议
Socket.IO 3.0.3存在已知的多连接会话串扰bug,可升级到3.1.2+的同大版本稳定版,无需修改现有业务逻辑即可规避底层框架问题。
内容的提问来源于stack exchange,提问作者empiricalDev
相关产品推荐
相关产品推荐

