使用ws库的WebSockets如何判断连接是客户端还是服务端关闭
结论
没有可通过close事件参数直接判断关闭发起方的原生方法,最可靠的实现方案就是额外标记服务端是否发起过关闭操作。
原因说明
WebSocket协议本身的关闭流程是双向交互的,ws库socket.on('close', (code, reason, wasClean) => {})回调里的code和reason参数,永远是对端发送的关闭帧携带的内容,而非本端发起关闭时设置的值:
- 若服务端主动调用
socket.close(4001, '自定义原因'),这个4001码只会被客户端收到,服务端侧的close事件拿到的code是客户端回复的关闭帧携带的值;如果客户端没有返回符合预期的关闭帧,就会返回默认的1005(表示未收到对端关闭码),这是协议的正常表现,不是库的bug。 - 三个原生回调参数里没有任何字段标识关闭操作是本端还是对端发起的。
推荐实现方式
- 自定义标记方案(最常用)
直接给socket实例挂载自定义属性,或者用WeakMap存储标记避免污染实例:
// 方式1:直接挂载属性 socket.isServerInitiatedClose = false // 服务端主动关闭前修改标记 socket.isServerInitiatedClose = true socket.close(4001, '服务端主动关闭') // close事件中判断 socket.on('close', (code) => { if (socket.isServerInitiatedClose) { // 服务端主动关闭 } else { // 客户端主动关闭 } }) // 方式2:用WeakMap存储,避免污染socket实例 const serverCloseMap = new WeakMap() // 主动关闭前设置 serverCloseMap.set(socket, true) socket.close(4001, '服务端主动关闭') // 事件中判断 socket.on('close', () => { if (serverCloseMap.has(socket)) { // 服务端主动关闭 serverCloseMap.delete(socket) // 清理内存 } else { // 客户端主动关闭 } })
不建议使用ws库的私有属性(比如_closeFrameSent等)判断,私有属性没有版本兼容性保障,后续版本升级可能失效。
内容的提问来源于stack exchange,提问作者Amaterasu
相关产品推荐
相关产品推荐

