WebSocket upgrade阶段socket.write返回401时ws客户端无法接收响应问题
ws客户端鉴权失败响应问题解答
1. socket.write('HTTP/1.1 401 Unauthorized\r\n\r\n') 代码作用
WebSocket连接建立的第一步是客户端向服务端发送HTTP协议升级请求,只有服务端返回101 Switching Protocols状态码,才会完成协议升级,建立长连接。
这行代码的作用是在HTTP层面直接拒绝客户端的升级请求:
- 按照HTTP协议格式返回401未授权的响应状态行
- 末尾的
\r\n\r\n是HTTP协议规定的响应头结束标记,告诉客户端响应头已经发送完毕 - 后续调用
socket.destroy()直接断开TCP连接,不会进入WebSocket协议处理流程,本质就是明确告知客户端本次请求鉴权失败,拒绝建立WebSocket连接。
2. 客户端无法在error回调中拿到响应内容的原因
ws库的error事件仅用于通知连接过程出现通用错误,不会暴露HTTP升级阶段的原始响应细节。鉴权失败时服务端返回的是HTTP层的响应,还没进入WebSocket协议交互阶段,所以error事件回调里的event对象不会携带这段HTTP响应内容。
3. 客户端正确获取鉴权失败响应的方法
监听ws实例的unexpected-response事件即可,该事件专门在HTTP升级阶段未返回101状态码时触发,回调中可以拿到原生HTTP响应对象,直接读取状态码、状态信息和响应内容:
const WebSocket = require('ws'); const ws = new WebSocket('wss://your-service-address'); // 监听HTTP升级阶段的非预期响应 ws.on('unexpected-response', (req, res) => { // 直接读取HTTP状态码和状态信息,无需手动解析原始响应字符串 console.log('请求失败,状态码:', res.statusCode); console.log('状态信息:', res.statusMessage); // 此处会输出 Unauthorized // 如果服务端返回了响应体,可通过以下方式读取 let responseBody = ''; res.on('data', chunk => { responseBody += chunk.toString(); }); res.on('end', () => { console.log('响应体内容:', responseBody); }); }); ws.onerror = (err) => { // 此处仅能拿到通用连接错误信息,无法获取HTTP响应细节 console.log('连接异常:', err.message); };
注意:示例服务端代码中仅返回了401响应头,没有写入任何响应体内容,所以上述代码读取responseBody会得到空字符串,属于正常情况,直接通过
res.statusCode === 401即可判定为鉴权失败。
内容的提问来源于stack exchange,提问作者Sever
相关产品推荐
相关产品推荐

