WebSocket连接成功后立刻断开,主因是握手失败:服务端未返回101状态码及Upgrade/Connection头,或代理未正确配置升级头、超时设置,或同源策略、Origin校验、NAT超时等导致静默中断。

WebSocket连接成功后立刻断开,基本不是心跳没配,而是压根没真正“成功”——握手阶段就失败了。
检查浏览器 Network 中是否返回 101 状态码
连接“闪断”最常见原因是服务端没完成协议升级。浏览器发的是 HTTP Upgrade 请求,但服务端回了个 200、400 或 502,或者压根没回 Upgrade 头,连接就会在瞬间关闭。
- 打开 DevTools → Network → 过滤
WS类型请求 - 点开该连接,看
Response Headers里有没有Upgrade: websocket和Connection: Upgrade - 确认状态行是
HTTP/1.1 101 Switching Protocols,不是其他任何状态码 - 如果用 Nginx 代理,必须显式配置
proxy_set_header Upgrade $http_upgrade和proxy_set_header Connection "upgrade",漏一个或写成$upgrade(少http_)都会失效
验证 URL 协议、域名、端口是否与当前页面同源
WebSocket 受同源策略约束,但比普通 AJAX 更严格:协议(ws/wss)、主机名、端口三者必须完全一致,否则连接会被静默拒绝或立即中断。
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
- HTTPS 页面中使用
ws://→ 浏览器直接阻止,不报错也不触发onerror - 页面在
https://app.example.com:8080,但 WebSocket 地址是wss://api.example.com→ 域名不一致,Origin 校验失败 - 本地开发时用
localhost但服务端只监听127.0.0.1,或反之 → 连接被 TCP 层拒绝,表现为快速onclose且event.wasClean === false
排查服务端 Origin / Token / IP 校验逻辑
很多 WebSocket 服务端在收到 upgrade 请求后,会立即校验 Origin 头、Authorization token 或 IP 白名单。任一不通过,就直接 close socket,不等客户端发任何消息。
- 查服务端日志,搜索关键词:
origin mismatch、invalid token、ip blocked、auth failed - 前端可临时在请求 URL 后加测试参数,如
?debug=1,让服务端绕过部分校验用于定位 - 注意:某些框架(如 Spring WebSocket)默认开启
allowedOrigins检查,若未显式配置为*或白名单,Origin不匹配即拒连
确认 Nginx / ALB / SLB 是否透传 Upgrade 并禁用超时
即使握手成功,反向代理也可能在几秒内主动 RST 连接——尤其当你没改默认配置时。它把 WebSocket 当普通 HTTP 处理,60 秒无数据就 kill。
-
proxy_read_timeout和proxy_send_timeout必须都 ≥ 心跳间隔 × 2 + 缓冲(例如心跳 30s,这里至少设90) - 仅配
proxy_http_version 1.1不够,必须同时有那两个proxy_set_header,且不能有拼写错误或多余空格 - ALB/SLB 类产品需开启“WebSocket 支持”开关(AWS ALB 默认关闭),否则 upgrade 请求会被转成 HTTP/1.0 回复,必然失败
- 用
tshark -f "tcp port 8080"抓包,若看到 FIN/RST 来自代理机器 IP,就是它下的手
真正难排查的,是那些不报错、不打日志、甚至不触发 onclose 的情况:比如 iOS Safari 切后台 30 秒后静默回收连接,或运营商 NAT 超时导致下次发消息才暴露为 1006。这时候不能只等断连再响应,得在每次 send() 前检查 ws.readyState === WebSocket.OPEN,并主动补心跳和重连逻辑。

















