Node.js/WS:如何在服务端抛出可被客户端处理的错误?
解决WebSocket连接数超限后触发客户端onerror的问题
我来帮你搞定这个问题——你想在WebSocket连接数超过2个时让客户端的onerror方法捕获错误,但直接在服务端抛错根本传不到客户端,对吧?这是因为在ws包的connection事件回调里直接throw错误,只会触发服务端的异常(如果没捕获的话),并不会通过WebSocket协议把错误通知给客户端。下面是具体的实现方案:
核心思路
当新连接进来后,先检查当前总连接数是否超过限制:
- 如果超限,先给客户端发送错误提示(可选但友好)
- 用带错误码的关闭帧主动断开连接,触发客户端的
onerror和onclose事件 - 及时从服务端的连接集合中移除这个超限连接
服务端代码(server.js)
const WebSocket = require('ws'); const theWebSocketServer = new WebSocket.Server({ port: 8080 }); theWebSocketServer.on('connection', function connection(websocket) { // 注意:ws的clients是Set对象,用size获取数量,不是length! if (theWebSocketServer.clients.size > 2) { // 1. 先给客户端发送错误原因(可选,客户端可通过onmessage接收) websocket.send(JSON.stringify({ error: '连接数已达上限,最多允许2个连接' })); // 2. 发送带自定义错误码的关闭帧 // 4001属于WebSocket私有错误码范围(4000-4999),适合业务自定义错误 websocket.close(4001, '连接数超限'); // 3. 手动从连接集合移除当前连接(close后会自动移除,但提前处理更稳妥) theWebSocketServer.clients.delete(websocket); return; } // 正常连接的后续处理逻辑 console.log('新连接建立,当前连接数:', theWebSocketServer.clients.size); websocket.on('message', (data) => { console.log('收到客户端消息:', data.toString()); }); websocket.send('连接成功'); });
客户端代码示例
要确保客户端同时监听onerror和onclose(不同环境下触发逻辑可能有差异):
const ws = new WebSocket('ws://localhost:8080'); // 监听错误事件 ws.onerror = (error) => { console.error('WebSocket错误捕获:', error); }; // 监听关闭事件,处理服务端发送的错误码和原因 ws.onclose = (event) => { if (event.code !== 1000) { // 1000是正常关闭码 console.error('连接异常关闭:', event.reason, '错误码:', event.code); } }; // 监听服务端发送的错误消息 ws.onmessage = (event) => { try { const data = JSON.parse(event.data); if (data.error) { console.error('服务端返回错误:', data.error); } else { console.log('服务端消息:', event.data); } } catch (e) { console.log('服务端消息:', event.data); } };
关键注意点
- 不要直接throw错误:服务端的
throw只会在自己的进程里触发异常,不会传递给客户端,必须通过WebSocket协议帧主动通知 - 使用clients.size而非length:ws包的
server.clients是一个ES6 Set对象,获取数量要用size属性,你之前的length写法是错误的,会导致判断不准确 - 自定义错误码:选择4000-4999范围内的错误码,这是WebSocket协议预留的私有业务错误码区间,避免和标准错误码冲突
- 客户端双监听:部分浏览器/环境下,服务端主动发送错误关闭帧会触发
onerror,但有些只会触发onclose,所以同时监听两个事件更稳妥
内容的提问来源于stack exchange,提问作者Anna Jeanine




