Node.js使用ws库开发WebSocket服务端 关闭事件缺少自定义原因
问题原因分析
ws库的close事件回调第二个参数reason默认是Buffer类型,直接打印如果没有转字符串会显示为Buffer对象而非可读文本,若浏览器确实未传递则为空Buffer。
- WebSocket协议规定关闭原因的字符串长度不能超过123字节,超出的话会被直接丢弃。
- 你当前的关闭逻辑绑定在
onunload/页面关闭事件中,出于性能和安全限制,绝大多数浏览器会主动丢弃页面卸载阶段WebSocket.close调用传入的自定义code和reason,直接使用默认关闭码关闭连接,不会传递自定义内容。
- 你当前的关闭逻辑绑定在
解决方案
1. 常规关闭场景(非页面卸载时主动触发关闭)
先将服务端收到的reason转为UTF-8字符串即可正常读取,修改服务端onSocketClose回调:
function onSocketClose(code, reason) { // 将Buffer转为UTF-8字符串 const reasonStr = reason.toString('utf8'); console.log("Closing open web socket", code, reasonStr); console.log("Closed web socket."); }
2. 页面卸载场景的兼容处理
浏览器限制无法通过close方法传递自定义reason,改为在关闭连接前先主动发送一条携带关闭原因的消息,服务端暂存该原因后再处理关闭逻辑:
修改客户端closeSocket方法:
function closeSocket(reason) { if (reason) { console.info("Closing socket due to:", reason); } else { reason = "Unknown reason"; } // 连接处于打开状态时先发送关闭原因 if (webSocket.readyState === WebSocket.OPEN) { webSocket.send(JSON.stringify({ type: 'socketClose', reason: reason })); } webSocket.onclose = function (ev) { console.info("Websocket closed."); }; webSocket.close(1001, reason); }
修改服务端逻辑,暂存对应连接的关闭原因:
wss.on("connection", function (ws) { // 存储当前连接的自定义关闭原因 let customCloseReason = ''; ws.on("message", function (data) { try { const msg = JSON.parse(data.toString()); if (msg.type === 'socketClose') { customCloseReason = msg.reason; } } catch (e) {} console.log("received: %s", data); }); function onSocketClose(code, reason) { // 优先取自定义的关闭原因,没有再用协议传递的 const finalReason = customCloseReason || reason.toString('utf8'); console.log("Closing open web socket", code, finalReason); console.log("Closed web socket."); } ws.on("close", onSocketClose); });
内容的提问来源于stack exchange,提问作者Daniele Tentoni
相关产品推荐
相关产品推荐

