socket.io开发疑问:是否需将路由处理函数包裹在io.on('connection')内?
结论先行:不推荐将路由放在
io.on('connection')回调内,该写法存在严重逻辑问题,有更合理的优化方案 为什么不能把路由写在connection回调里
- 每有一个新的Socket客户端连接,就会重复注册一次Express路由。多次注册的同名路由会按顺序全部触发,会导致单次请求重复执行业务逻辑、内存泄漏、响应异常等不可预期的问题
- 完全解决不了你担心的「连接未建立导致emit失败」的问题,逻辑上完全不相关
你顾虑的问题的实际解决方案
你担心的问题可以拆分为两种场景,分别对应不同的处理方案:
情况1:担心服务端io实例未初始化,调用emit报错
这个问题不存在:new Server()初始化io实例、将io挂载到app对象、注册Express路由三个操作都是同步执行的,等到服务端启动完成可以接收HTTP请求时,io实例已经完全初始化完成,调用req.app.io.emit不会出现实例不存在的报错,最多只是当前没有在线的客户端接收事件而已,emit操作本身不会抛出异常。
情况2:担心客户端Socket连接未建立,收不到服务端emit的事件
这个是实际可能出现的场景,对应优化方案如下:
客户端侧调整请求触发时机
确保Socket连接成功后再发起业务请求,从根源上避免「请求发了、Socket还没连上」的问题:
socket = io(`http://localhost:${port}`, { transports: ['websocket'] }) socket.on('something', (data) => { doSomethingMoreWith(data) }) // 等Socket连接成功后再发起fetch请求 socket.on('connect', () => { fetch('/something', ....) })
服务端侧增加定向推送和存在性判断
如果你的业务需要把事件推送给发起请求的特定客户端,而不是广播给所有在线客户端,可以在请求中携带当前Socket的id作为标识,服务端先判断对应Socket是否在线再推送:
客户端代码调整:
socket.on('connect', () => { fetch('/something', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ socketId: socket.id, // 其他业务参数 }) }) })
服务端代码调整:
app.post('/something', (req, res) => { const { socketId, ...otherParams } = req.body const data = doSomethingWith(otherParams) // 先判断目标Socket是否在线,再定向推送 if (io.sockets.sockets.has(socketId)) { io.to(socketId).emit('something', data) } res.sendStatus(200) })
内容的提问来源于stack exchange,提问作者user2272048
相关产品推荐
相关产品推荐

