WebSocket连接需先完成HTTP升级握手:客户端必须发送含Upgrade: websocket、Connection: Upgrade、Sec-WebSocket-Key(16字节随机Base64)、Sec-WebSocket-Version: 13及可选Origin的GET请求;服务端须校验并返回101状态码及合法Sec-WebSocket-Accept响应头,任一缺失或错误均导致400/426等握手失败。

WebSocket连接不是直接建立的,而是通过一次HTTP升级握手完成的——没走通这一步,后续所有通信都不存在。
客户端发的GET请求里必须带哪些Header
浏览器或ws、websockets库发起连接时,底层会自动构造一个HTTP GET请求,但你得知道它到底塞了什么进去,否则遇到400或426错误根本无从排查:
-
Upgrade: websocket—— 缺了这个,服务器压根不认这是WebSocket请求 -
Connection: Upgrade—— 和上面配对,单独写keep-alive没用 -
Sec-WebSocket-Key—— 16字节随机数据Base64编码,比如dGh0bWVuf3JlZGgiMzE4NzY3NzI4NzE=;服务端要用它拼上固定GUID再SHA-1+Base64生成Sec-WebSocket-Accept -
Sec-WebSocket-Version: 13—— 当前唯一通用版本,写12或14会被拒绝 -
Origin(可选但建议)—— 防跨站滥用,后端常据此做白名单校验
漏掉任意一个必需字段,服务器大概率返回400 Bad Request或直接断连。
服务器响应101状态码时的校验逻辑
服务端收到请求后,不会直接返回101 Switching Protocols,而是先执行一串验证:
- 检查
Upgrade和Connection是否严格匹配,大小写敏感 - 解析
Sec-WebSocket-Key是否为合法Base64且长度够16字节原始数据 - 计算
Sec-WebSocket-Accept:把Key拼上"258EAFA5-E914-47DA-95CA-C5AB0DC85B11",SHA-1哈希后再Base64编码 - 若启用了子协议(
Sec-WebSocket-Protocol),要确认双方支持交集
任一环节失败,就可能抛InvalidHandshake异常(在websockets库中)或静默关闭连接——此时客户端看到的是EventTarget.onerror或onclose事件,没有具体错误信息。
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
为什么本地能连通但部署到Nginx后就失败
这不是代码问题,是反向代理没透传WebSocket头部导致的典型现象:
- Nginx默认不转发
Upgrade和Connection头,需显式配置:proxy_set_header Upgrade $http_upgrade;和proxy_set_header Connection "upgrade"; - 如果用了
proxy_http_version 1.1但没配上面两行,请求会卡在HTTP 1.1长连接,永远等不到101响应 - Cloudflare等CDN默认拦截WebSocket握手,需在仪表盘开启WebSocket支持(开关名通常是“WebSocket”或“Enable WebSocket”)
- 某些企业防火墙会主动丢弃含
Upgrade头的请求,需联系运维放行
这类问题的表现是:前端new WebSocket("wss://...")后长时间无响应,Network面板里看不到101响应,只有pending状态的GET请求。
用Python websockets库调试握手失败
当你用websockets.connect()连不上时,别只看ConnectionRefusedError,重点抓握手阶段的异常:
- 捕获
websockets.exceptions.InvalidHandshake——说明服务器返回了非101响应,或响应头缺失/格式错误 - 启用日志:
logging.basicConfig(level=logging.DEBUG),能看到build_request和check_response的详细过程 - 检查服务端
handshake.py里的check_request函数是否因Origin不匹配或Sec-WebSocket-Key非法而提前退出 - 用
curl -i -N -H "Connection: Upgrade" -H "Upgrade: websocket" -H "Sec-WebSocket-Key: dGh0bWVuf3JlZGgiMzE4NzY3NzI4NzE=" -H "Sec-WebSocket-Version: 13" http://localhost:8000/ws手动模拟握手,观察原始响应
真正难定位的不是连接失败,而是握手成功后立刻断开——那往往意味着帧解析层出错,已超出握手协议范畴。

















