如何将Express路由处理器中的数据传递给Socket.io处理函数?
数据从Express路由传递到Socket.io处理函数的解决方案
核心原理
Express的路由请求和Socket.io的连接请求是两个独立的HTTP交互,二者没有直接的上下文共享通道,不需要通过全局变量或者路由内挂载Socket.io逻辑实现参数传递,可以通过握手阶段读取公共存储的Cookie或者前端连接时主动传参两种方式实现,完全避免多用户数据冲突问题。
方案1:Socket.io握手阶段读取Cookie(适配现有代码,无需修改前端)
你已经把roomName和currentUser存在了Cookie中,同域下Socket.io发起连接请求时会自动携带所有对应域名的Cookie,直接在连接回调中解析握手请求的Cookie即可:
// 先安装cookie解析依赖:npm install cookie const cookie = require('cookie'); io.of('/game').on('connection', socket => { console.log('a user connected'); // 解析握手请求头携带的Cookie const cookies = cookie.parse(socket.handshake.headers.cookie || ''); const currentUser = cookies['current_user']; const roomName = cookies['room_name']; // 非法连接直接断开,避免后续报错 if (!roomName || !currentUser) { socket.disconnect(); return; } socket.join(roomName); io.of('/game').in(roomName).emit('join', currentUser); (async() => { const sockets = await io.of('/game').in(roomName).fetchSockets(); console.log(sockets.length); })(); socket.on('disconnect', () => { console.log('user disconnected'); }); });
该方案的优势是不需要修改任何前端逻辑,每个连接独立读取自身携带的Cookie,完全不会出现多用户数据互相覆盖的问题。如果使用了签名Cookie,调用cookie-parser的signedCookie方法传入你的加密密钥解析即可。
方案2:前端连接时主动传参(适合未存入Cookie的参数场景)
如果参数没有存储在Cookie中,你可以在前端初始化Socket.io连接时,将所需参数放在查询字段中传递:
前端代码(pages/game页面的JS逻辑)
// 从服务端渲染的模板中拿到参数,示例为EJS模板写法 const roomName = "<%= room %>"; const currentUser = "<%= currentUser %>"; // 连接时携带查询参数 const socket = io('/game', { query: { roomName: roomName, currentUser: currentUser } });
后端Socket.io逻辑
io.of('/game').on('connection', socket => { // 从握手查询字段中读取参数 const { roomName, currentUser } = socket.handshake.query; // 后续校验、加入房间逻辑和方案1完全一致 });
注意事项
不要将Socket.io的connection事件监听写在Express路由内部,会导致每次请求路由都重复绑定事件,引发内存泄漏和重复触发逻辑的问题。
内容的提问来源于stack exchange,提问作者William Jones
相关产品推荐
相关产品推荐

