如何在Node.js服务重启前关闭WebSocket客户端的所有现有连接
错误原因
你调用close()报错的核心问题是:存入sockets数组的是WebSocketClient实例,该实例仅用于发起连接,本身没有close方法。真正控制连接的close方法挂载在connect事件回调返回的connection对象上。
代码修复
以下是调整后的可运行代码:
const WebSocketClient = require('websocket').client; const axios = require('axios'); let sockets = []; // 移除无用的client入参 function openSocket(id){ const client = new WebSocketClient(); client.on('connectFailed', function(error) { console.log('Connect Error 1: ' + error); }); client.on('connect', function(connection) { console.log('WebSocket Client Connected for id:' + id); // 将可用的connection存入数组 sockets.push(connection); connection.on('error', function(error) { console.log("Connection Error 2: " + error.toString()); }); connection.on('close', function() { console.log('echo-protocol Connection Closed for id:' + id); // 连接关闭后从数组中移除,避免存储无效引用 sockets = sockets.filter(item => item !== connection); }); connection.on('message', function(message) { let {utf8Data:socketResData} = message; console.log(socketResData); }); function subscribe(){ if (connection.connected) { connection.send(JSON.stringify( { action: "SubscribeToAuction", data: id } )); } } subscribe(); function pingServer() { if (connection.connected) { connection.send(JSON.stringify( { action: "Ping", } )); // 保存定时器id,连接关闭时清除避免内存泄漏 connection.pingTimer = setTimeout(pingServer, 540000); } } pingServer(); }); // 这里替换成你实际的socketUrl client.connect(socketUrl,null,{"x-forwarded-client-id":id},null); } // 封装关闭所有连接的方法 function closeAllSockets() { sockets.forEach(connection => { if (connection.connected) { // 清除心跳定时器 clearTimeout(connection.pingTimer); connection.close(); } }); // 清空数组 sockets = []; } function run(){ // 每次新建连接前先关闭已有连接,避免重复创建 closeAllSockets(); // 这里替换成你实际的请求参数 axios(url, { method: 'GET', headers: { authority, 'x-forwarded-client-id': id, }, }).then(res => { const auction = res.data.models.HomePageModel.upcomingModel.upcomingAuctions; auction.forEach(el => { openSocket(el.auctionUuid) }); }).catch(err => console.log(err)) } run(); // 监听进程退出信号,服务重启/停止时主动关闭所有连接 process.on('SIGINT', closeAllSockets); process.on('SIGTERM', closeAllSockets); // 测试用的关闭逻辑,可保留验证 setTimeout(() => { closeAllSockets(); console.log('所有连接已关闭'); },10000)
场景最佳实践
- 连接去重:可以用Map替代数组存储连接,key为auctionUuid,建立连接前先判断对应key是否已存在活跃连接,避免重复订阅相同资源
- 重连逻辑:单个连接断开后可按指数退避策略重连,避免频繁请求第三方服务
- 状态监控:定期遍历连接列表,清理长时间无响应的死连接
- 优雅退出:所有进程退出场景都要主动关闭连接,避免服务端残留半开连接
内容的提问来源于stack exchange,提问作者sameed ul hassan
相关产品推荐
相关产品推荐

