WebSocket连接短暂断开,如何维持长连接及架构相关咨询
WebSocket短暂连接后断开问题排查与解答
问题描述
尝试连接API中的WebSocket,但仅能短暂建立连接后就断开。以下是相关代码与日志:
前端HTML脚本代码
const ws = new WebSocket('ws://localhost:1337') ws.addEventListener('open', (event) => { ws.send(JSON.stringify({title: 'like that', message: 'gimme update'})); }) ws.addEventListener('close', (close) => { console.log(JSON.stringify(close)) }) ws.addEventListener('message', (event) => { const dataFromServer = JSON.parse(event.data); console.log('Message from server', JSON.parse(event.data)) const h1 = document.getElementById('changeHere'); h1.innerText = `Changing: ${dataFromServer.statusId}` })
后端代码
... const websocket = new WebSocket.Server({ server: httpServer }); const TAG_WEBSOCKET = '[WEBSOCKET]'; websocket.on('connection', (connection) => { connection.on('error', (err) => console.error); logger.info('client connected'); connection.send('message'); emitter.on('updateStatus', (data) => { logger.info(TAG_WEBSOCKET + 'Update status for ' + data.id); connection.send(JSON.stringify(data)); }); connection.on('close', () => { logger.info('connection closed'); emitter.removeAllListeners(); }); }); httpServer.listen(PORT, () => { logger.info(`${TAG} Server running on port: ${PORT}`); });
后端日志
2023-01-04 21:28:44 [info] client connected info: Client disconnect: undefined error: Can not find client undefined on disconnect 2023-01-04 21:28:44 [info] connection closed
咨询问题:
- 如何实现客户端在线时保持WebSocket长连接?
- 该问题是否与API被大量非WebSocket客户端使用有关?
- 是否需要为WebSocket单独搭建专用API?
解决方案与解答
1. 实现WebSocket长连接的关键修复与优化
当前连接断开的核心原因是代码逻辑错误,需针对性修复:
- 修复JSON解析错误:后端在连接建立后发送的
'message'是纯字符串,前端尝试用JSON.parse解析会抛出语法错误,可能触发连接异常。需将后端初始消息改为合法JSON:
前端也可增加解析容错:// 后端修改初始发送内容 connection.send(JSON.stringify({type: 'init', message: 'connected'}));ws.addEventListener('message', (event) => { let dataFromServer; try { dataFromServer = JSON.parse(event.data); console.log('Message from server', dataFromServer); const h1 = document.getElementById('changeHere'); if (dataFromServer.statusId) { h1.innerText = `Changing: ${dataFromServer.statusId}`; } } catch (e) { console.warn('Received non-JSON message:', event.data); } }) - 修正监听器移除逻辑:后端在
close事件中调用emitter.removeAllListeners()会移除所有updateStatus事件的监听器,导致其他在线客户端无法接收消息,还可能间接影响当前连接生命周期。应改为移除当前连接对应的特定监听器:websocket.on('connection', (connection) => { // 单独定义监听函数,方便后续移除 const updateStatusHandler = (data) => { logger.info(TAG_WEBSOCKET + 'Update status for ' + data.id); connection.send(JSON.stringify(data)); }; emitter.on('updateStatus', updateStatusHandler); connection.on('close', () => { logger.info('connection closed'); // 仅移除当前连接的监听器 emitter.off('updateStatus', updateStatusHandler); }); }); - 增加心跳机制:避免网络超时或中间设备主动断开空闲连接,实现心跳交互:
- 前端:每隔30秒发送心跳包
let heartbeatTimer; ws.addEventListener('open', () => { heartbeatTimer = setInterval(() => { if (ws.readyState === WebSocket.OPEN) { ws.send(JSON.stringify({type: 'ping'})); } }, 30000); }); ws.addEventListener('close', () => { clearInterval(heartbeatTimer); }); - 后端:收到心跳包后返回响应
connection.on('message', (message) => { const data = JSON.parse(message); if (data.type === 'ping') { connection.send(JSON.stringify({type: 'pong'})); } // 处理其他业务消息 });
- 前端:每隔30秒发送心跳包
- 完善错误处理:后端错误监听需传入错误参数,便于排查问题:
connection.on('error', (err) => console.error('WebSocket connection error:', err));
2. 与大量非WebSocket客户端的关联性
普通HTTP请求(非WebSocket客户端)不会直接导致WebSocket连接断开,只要服务器资源(CPU、内存、文件描述符)充足,两者可以共存。从当前日志看,连接后立即断开更可能是代码逻辑错误导致,而非非WebSocket客户端的影响。若服务器资源紧张(如CPU占用过高),可能间接影响连接稳定性,可通过监控服务器资源使用情况排除该因素。
3. 是否需要单独搭建WebSocket专用API
不是必须的,需根据业务规模与需求判断:
- 无需拆分场景:当前业务量不大,普通HTTP请求与WebSocket的资源需求差异小,共用一个服务器可简化部署与维护。
- 建议拆分场景:
- WebSocket并发量极高,需要独立扩容或资源隔离;
- 普通HTTP API的中间件(如认证、CORS)与WebSocket逻辑冲突,拆分后可简化配置;
- 业务逻辑复杂度高,拆分后便于单独维护与迭代。
当前问题属于代码逻辑错误,优先修复代码即可,无需立即拆分API。
内容的提问来源于stack exchange,提问作者Lucas Lima
相关产品推荐
相关产品推荐

