WebSocket upgrade failed:升级握手失败的检查步骤
WebSocket upgrade failed严重程度 HighHTTP 到 WebSocket 的协议升级没有完成,服务端返回的不是 101。最可能是路径、Host 或中间层(CDN、反向代理)配置与服务端 WebSocket 入口不一致;第一步是运行检测拿到服务端实际返回的状态码。
结论
WebSocket 连接的第一步是一个特殊的 HTTP 请求:客户端带着 Upgrade: websocket 头去请求服务端,期待收到 101 Switching Protocols。这条报错说明 101 没有到来——服务端(或它前面的某一层)返回了别的状态码,或者干脆没有正确响应。升级失败几乎总是配置问题而不是网络质量问题,因此第一步不是换网络,而是拿到实际返回的状态码。
适用环境
- 所有平台的 WebSocket 客户端
- 走 CDN 或反向代理的 wss:// 服务(最常见的故障场景)
一分钟快速判断
运行:
connproof websocket wss://你的地址/路径按返回的状态码对号入座:
| 状态码 | 含义 | 首先检查 |
|---|---|---|
| 404 | 路径不存在 | 客户端路径与服务端配置是否逐字符一致 |
| 400 | 升级头被剥离或畸形 | 中间代理是否透传 Upgrade/Connection 头 |
| 403 | 被拒绝 | Host/SNI/来源校验,CDN 防护规则 |
| 502/503/504 | 网关背后服务不可用 | 源站 WebSocket 服务是否在运行 |
| 200 | 被当成普通 HTTP 处理 | 中间层未开启 WebSocket 支持 |
这条错误代表什么
RFC 6455 规定的升级流程要求请求逐跳传递 Upgrade: websocket 与 Connection: Upgrade 头。这两个头是逐跳头——任何一层反向代理如果不显式配置转发,它们就会被丢弃,后端收到的只是一个普通 GET 请求,自然不会返回 101。这就是为什么 Nginx、CDN、负载均衡器是这条错误的高发地:链路上每多一层,就多一处可能吞掉升级头的地方。
ConnProof 如何判断
ConnProof 执行真实的 RFC 6455 握手,而不是模拟:发送带随机 Sec-WebSocket-Key 的升级请求,校验响应状态码与 Sec-WebSocket-Accept 的哈希值。报告中的证据包括:
- 升级响应状态码(这是最重要的一条证据);
- Accept 头校验结果(101 但校验失败说明中间层伪造了响应);
- 建连与升级各自的耗时;
- 升级成功后连接是否立即被关闭(那是另一条错误:WS-002)。
最常见原因
- 路径或 Host 不一致:客户端配置里的路径与服务端 WebSocket 入口不同(哪怕只差一个斜杠或大小写)。
- 反向代理未透传升级头:Nginx 需要显式的
proxy_set_header Upgrade $http_upgrade;与proxy_set_header Connection "upgrade";,缺一不可。 - CDN 未开启 WebSocket:部分 CDN 套餐默认关闭 WebSocket 支持,或仅对特定端口开放。
- 服务端只监听在其他路径/端口:服务端配置改动后客户端没有同步。
Windows / macOS / Linux 排查步骤
桌面端步骤一致,核心是三次对比检测:
- 原样检测:
connproof websocket wss://域名/路径,记录状态码; - 换路径检测:故意在路径后加一段乱码再测。如果两次返回相同的非 101 状态码,说明请求根本没到达 WebSocket 服务(中间层拦截);如果乱码路径 404 而正确路径返回别的错误,说明路由是通的,问题在升级环节本身;
- 绕过 CDN 检测(服务维护者适用):把域名临时解析到源站 IP 复测。源站 101 而 CDN 失败 → 问题锁定在 CDN 配置。
普通用户如果无法做第 3 步,把第 1、2 步的状态码证据发给服务方即可,这两个数字足够服务端定位。
手机端排查步骤
- 手机客户端遇到 WS-001 时,优先用桌面设备跑一次
connproof websocket拿到状态码——手机客户端的日志通常不显示这一信息; - 确认手机客户端配置(路径、Host、TLS 开关)与桌面成功配置完全一致;
- Wi-Fi 与蜂窝下结果不同的情况较少见于 WS-001,若出现,按 TLS handshake timeout 的网络对比法处理。
给服务维护者:反向代理配置检查清单
如果你维护这个 WebSocket 服务,按下面的清单核对代理层配置。以 Nginx 为例,一个能正确转发升级请求的 location 至少需要:
location /你的路径 {
proxy_pass http://后端地址;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_read_timeout 300s;
}2
3
4
5
6
7
8
逐项含义:proxy_http_version 1.1 是前提(HTTP/1.0 不支持升级);两个 proxy_set_header 负责把逐跳头重新加回去;proxy_read_timeout 决定空闲连接能活多久,默认 60 秒常常是"连上一分钟就断"的元凶。改完配置后,用 connproof websocket 从公网侧验证,而不是只在服务器本机 curl——很多配置问题只在经过完整链路时才暴露。
走 CDN 的服务还要多查一层:确认所用套餐和加速区域确实支持 WebSocket,并在 CDN 控制台里为对应域名显式开启;部分 CDN 对免费套餐只在特定端口(如 443、8443)支持升级请求,源站监听在其他端口时需要改回源端口配置。CDN 侧的缓存规则也可能误伤升级请求——把 WebSocket 路径加入"不缓存"规则是稳妥做法。逐层验证的顺序永远是:先源站直连,再经 CDN,最后经客户端完整链路,每层各测一次就能锁定断点。
如何区分本地问题和节点问题
| 证据 | 更可能是 |
|---|---|
| 有明确的非 101 状态码 | 服务端/中间层配置(不是你的网络) |
| 完全无响应直到超时 | 网络层问题,转查 TLS-002 / TCP-001 |
| 多设备同一配置都失败 | 服务端配置 |
| 仅单台设备失败 | 该设备配置抄写错误 |
仍未解决时收集什么信息
- ConnProof 错误码(WS-001)与脱敏报告;
- 升级响应状态码(关键证据);
- 客户端名称和版本、操作系统版本;
- 问题开始时间(服务端是否恰好改过配置)。
禁止提交:完整订阅链接、密码、验证码、私钥、Token。路径中若含个人标识,脱敏报告会自动去除查询参数。
重新运行检测
connproof websocket wss://你的地址/路径 --hold 5000修复后应看到:升级成功(101)、Accept 校验通过、连接保持到设定时长后正常关闭。
相关文档
更新记录
- 2026-07-28:规则 v1 发布,建立状态码对照表与乱码路径对比法。