Node.js使用Socket.io刷新页面时socket连接数持续递增不释放问题排查
问题根因
- 核心错误是你将Socket.io全局实例的
connection事件监听逻辑放在了getPage路由处理函数中:每访问一次/temp页面(含刷新),就会给全局io实例新增一个重复的connection监听器,历史注册的监听器不会自动销毁。 - 每次有新的Socket连接建立时,所有已注册的connection监听器都会同时触发,因此你会看到刷新N次后,connect日志会打印N条,对应disconnect事件也会被绑定N次,每条日志数量和页面访问次数完全匹配。
- 每一个监听器都会持有对应socket实例的引用,导致断开的socket无法被垃圾回收,最终表现为连接数持续增长。
disconnect事件触发时socket本身已经在执行断开流程,你写的socket.disconnect(0)属于无效的冗余逻辑。
修复方案
将connection事件监听逻辑从路由处理函数中移出,在server.js中全局仅注册一次即可:
- 修改
server.js代码:
const app = express(); const server = require("http").createServer(app); const io = require("socket.io")(server); // 全局仅注册一次连接监听 io.on('connection', (socket) => { console.log('connect'); socket.on('disconnect', () => { console.log('disconnect'); }); }); app.use((req, res, next) =>{ req.io = io; next(); }); const temp = require("./routes/temp"); app.use("/temp", temp);
- 修改controller层
getPage代码,移除重复的监听逻辑:
getPage(req, res, io){ console.log('re'); // 剩余业务逻辑保留即可 }
补充注意事项
如果业务场景需要在页面请求时对应当前用户的socket实例做操作,不要重复注册connection监听,可通过如下方式实现:
- 建立全局Map存储用户标识与socket实例的映射关系
- 在全局connection监听中,将登录用户的id和socket绑定存入Map
- 路由处理时从请求中拿到用户id,再从Map中取出对应socket实例执行操作即可
内容的提问来源于stack exchange,提问作者재창킴
相关产品推荐
相关产品推荐

