使用express-ws搭建WebSocket,线上环境出现101错误求助
本地基于Node.js的WebSocket服务(express-ws搭建)与客户端(ws库)通信正常,但部署到线上后客户端抛出以下错误:
Error: Unexpected server response: 101
at ClientRequest. (C:\websites\api\node_modules\ws\lib\websocket.js:912:7)
at ClientRequest.emit (node:events:527:28)
at HTTPParser.parserOnIncomingClient [as onIncoming] (node:_http_client:631:27)
...(省略剩余堆栈信息)
结合你的服务端和客户端代码,以下是常见排查方向与解决方案:
1. 反向代理/负载均衡未配置WebSocket协议支持
线上环境常用的Nginx、云负载均衡等中间件,默认不会自动处理WebSocket的协议升级请求,需手动配置:
- 以Nginx为例,在对应location块添加WebSocket支持:
location /ws { proxy_pass http://你的后端服务地址; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; }
原因:WebSocket依赖HTTP 1.1的Upgrade和Connection头触发协议切换,若代理未转发这些头,客户端无法识别服务端返回的101响应。
2. 客户端连接URL协议不匹配
线上环境若采用HTTPS部署,客户端必须使用wss://协议(而非ws://)建立连接,否则会被浏览器/代理拦截:
- 检查环境变量
WEBSOCKET_SERVER和WEBSOCKET_TEST_SERVER的取值:- 服务端用HTTPS → 客户端URL:
wss://xxx-domain.com/ws - 服务端用HTTP → 客户端URL:
ws://xxx-domain.com/ws
- 服务端用HTTPS → 客户端URL:
3. 服务端监听地址限制
你的服务端代码未指定监听地址,线上环境可能默认仅监听127.0.0.1,导致外部无法访问:
- 修改服务端监听代码,指定监听所有网卡:
app.listen(port, '0.0.0.0', () => { console.log(`API app listening at http://0.0.0.0:${port}`); });
4. 防火墙/安全组端口拦截
线上服务器的安全组或防火墙可能未开放WebSocket服务端口,或拦截了Upgrade请求:
- 检查服务器安全组规则,开放服务使用的端口(TCP协议);
- 关闭服务器本地防火墙或添加对应端口的放行规则。
5. 依赖版本兼容性问题
线上安装的ws/express-ws版本可能与本地不一致,导致协议处理逻辑差异:
- 在package.json中锁定依赖版本:
"dependencies": { "express": "^4.18.2", "express-ws": "^5.0.2", "ws": "^8.14.2" }
- 重新安装依赖:
npm install
验证步骤
用curl直接测试服务端的WebSocket升级能力,判断问题出在服务端还是客户端:
curl -i -N -H "Connection: Upgrade" -H "Upgrade: websocket" -H "Sec-WebSocket-Version: 13" -H "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==" http://你的服务端地址/ws
若返回HTTP/1.1 101 Switching Protocols,说明服务端和代理配置正常,问题大概率在客户端;若返回其他状态码,优先排查服务端或代理配置。
内容的提问来源于stack exchange,提问作者Esther

