You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node websockets/ws库:如何区分主动关闭与对方关闭WSS连接?

解决ws库中区分主动/被动关闭连接及Close Code异常问题

我之前在使用ws库处理WSS流的时候,也踩过一模一样的坑——本来想通过传code和reason来区分关闭场景,结果要么没效果要么直接抛异常。结合官方文档和实际调试经验,给你整理几个靠谱的解决办法:

1. 先搞懂ws库关闭连接的正确姿势

你之前的误区可能是把onclose事件当成了可以传参数的方法,但实际上:

  • 主动关闭:必须调用实例的ws.close([code[, reason]])方法来发送关闭指令,这些参数会传递给对方,同时本地的onclose回调也会收到对应的code和reason。
  • 被动关闭:onclose回调里的code和reason是对方发送过来的,或者是连接异常时的系统默认值。

2. 用标记区分主动/被动关闭

最简单直接的方式是在主动关闭前设置一个全局标记,然后在onclose回调里检查这个标记:

const WebSocket = require('ws');

const ws = new WebSocket('wss://your-target-stream');
let isManualClose = false; // 标记是否是主动关闭

// 封装主动关闭函数
function manualClose(code = 1000, reason = 'Normal shutdown') {
  isManualClose = true;
  try {
    ws.close(code, reason);
  } catch (err) {
    console.error('主动关闭时出错:', err);
  }
}

// 监听关闭事件
ws.on('close', (code, reason) => {
  if (isManualClose) {
    console.log(`✅ 主动关闭连接 | Code: ${code}, Reason: ${reason.toString()}`);
  } else {
    console.log(`❌ 被动/异常关闭连接 | Code: ${code}, Reason: ${reason.toString()}`);
  }
  // 重置标记,避免重连时判断错误
  isManualClose = false;
});

// 示例:主动关闭(比如用户操作触发)
// setTimeout(() => manualClose(4001, '业务逻辑触发关闭'), 5000);

3. 解决Close Code触发异常的问题

ws库对Close Code的校验非常严格,不是随便传个整数就行,必须符合RFC 6455的规范:

  • 标准Code(1000-1015):只能用定义好的场景,比如1000是正常关闭,1001是端点离开,不能随便自定义。
  • 自定义Code(4000-4999):这部分是留给业务自定义的,比如4001可以代表“业务超时”,4002代表“权限不足”等。
  • 其他范围的Code:比如2000-3999、5000+都会直接触发异常,绝对不能用。

另外还要注意:reason字符串的长度不能超过123字节,否则也会抛出错误,所以尽量保持reason简洁。

4. 额外注意事项

  • 如果连接已经处于关闭状态,调用ws.close()会报错,所以最好在调用前先检查ws.readyState是否为WebSocket.OPEN。
  • 异常断开(比如网络中断)时,onclose的code可能是1006(连接异常关闭),这时候reason是空的,需要单独处理。

内容的提问来源于stack exchange,提问作者Birrel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 07:48:02