第一眼要确认浏览器是否发出握手请求及服务端是否返回101状态码;需在devtools network的ws标签页查看,若无记录则请求未发出,常见于协议/域名不匹配或url错误。

看 Network 面板里有没有 101 状态码
连接失败时,第一眼要确认的不是代码有没有错,而是浏览器到底发没发出握手请求、服务端回没回 101。打开 DevTools → Network → 切到 WS 标签页(不是 XHR 或 Fetch),刷新页面触发连接。如果连这条记录都看不到,说明请求压根没发出去——大概率是协议/域名不匹配被浏览器拦截,或 URL 写成了 ws:// 但页面是 HTTPS。
看到记录后点开,重点检查:
-
Response Headers里必须有HTTP/1.1 101 Switching Protocols - 必须包含
Upgrade: websocket和Connection: Upgrade - 若状态码是
400、426、502,说明服务端或代理没完成协议升级,不是心跳或业务逻辑问题
Nginx 反向代理是否透传 Upgrade 头
线上环境 WebSocket 连不上,90% 是 Nginx 没配对。它默认把 WebSocket 当普通 HTTP 处理,直接返回 200 或 502,根本不会转发给后端服务。检查你的 location 块里有没有这三行:
proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade";
漏掉任意一行,Upgrade 和 Connection 头就会丢失,服务端收不到升级信号,连接立刻断开。注意:$http_upgrade 是变量名,不能写成字面量 "Upgrade";Connection 的值必须带双引号,否则 Nginx 会忽略。
前端 new WebSocket() 传的 URL 是否可直连
常见错误是把后端服务监听地址(如 ws://localhost:8080/ws)硬编码进前端,部署后用户浏览器根本访问不到这个地址。WebSocket 地址必须是客户端网络可达的地址,比如:
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
- 开发时用
ws://192.168.1.100:8080/ws(非 localhost) - 生产环境用
wss://api.example.com/ws(和页面同源或显式配置 CORS) - 绝对不要在上线包里留
ws://127.0.0.1或ws://docker-host这类内部地址
验证方式很简单:在浏览器控制台手动执行 new WebSocket("your-url"),看 onerror 是否立即触发。如果触发,且控制台只显示 “failed” 没具体错误,基本就是 DNS 不通、端口被拦、或协议不匹配。
服务端是否校验 Origin 或 Token 失败
握手成功返回 101 后立刻断开,往往不是网络问题,而是服务端在升级完成后立即做了校验并主动关闭。典型表现是:Network 面板能看到 101,但 Frames 标签页空空如也,控制台出现 onclose 且 event.code 是 4001 或 4003。
这时必须查服务端日志,重点关注:
-
Origin头是否被拒绝(比如前端从https://app.com连,但服务端只允许https://admin.com) -
Authorization或查询参数里的token是否过期、签名错误、或未在请求头中传递(WebSocket 握手是 GET 请求,Token 放 header 或 query 都可以,但必须和服务端约定一致) - IP 白名单、User-Agent 限制等中间件拦截日志
特别注意:有些框架(如 Spring WebSocket)默认校验 Origin,而某些构建工具(如 Vite)开发服务器会改写该头,导致本地连不上——这不是 bug,是安全策略生效了。










