HTTP/2不支持WebSocket的Upgrade机制,需通过子域名隔离并强制降级至HTTP/1.1,Nginx须配置proxy_http_version 1.1及Upgrade、Connection头透传,或采用stream模块TCP透传。

HTTP/2 本身不支持 WebSocket 的传统 Upgrade 机制,这是协议层面的硬性限制,不是配置疏漏。要让 WebSocket 在 HTTP/2 环境下正常工作,核心思路是“隔离”或“降级”——把 WebSocket 流量从 HTTP/2 路径中分离出来,强制走 HTTP/1.1 协议栈。
明确区分协议路径:子域名或独立端口
最稳妥、生产环境推荐的做法是用子域名隔离流量。例如主站用 example.com(启用 http2),WebSocket 服务单独部署在 ws.example.com,并在其 server 块中完全禁用 HTTP/2:
- 移除 listen 指令中的
http2参数,只保留ssl - 确保该 server 块内所有 location 都配置了
proxy_http_version 1.1、proxy_set_header Upgrade $http_upgrade和proxy_set_header Connection "upgrade" - 避免在该 server 中混用其他需 HTTP/2 的功能(如 Server Push),防止隐式冲突
Nginx 中必须设置的关键代理头
即使已分离协议路径,反向代理层仍需显式透传升级信号。以下三行是 WebSocket 代理不可省略的基础配置:
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
-
proxy_http_version 1.1;—— 强制与后端通信使用 HTTP/1.1,绕过 h2 协议解析 -
proxy_set_header Upgrade $http_upgrade;—— 将客户端原始 Upgrade 头原样转发(注意变量名大小写) -
proxy_set_header Connection "upgrade";—— Connection 头值必须加英文双引号,否则 Nginx 会忽略或报错
额外建议加上 proxy_read_timeout 86400;,防止空闲连接被中间设备意外断开。
验证是否真正走通 WebSocket
不能只看浏览器控制台无报错,需分层确认:
- 在浏览器 Network 面板中找到 ws 连接,Protocol 列显示 websocket,状态码为 101 Switching Protocols
- 用 curl 模拟握手:
curl -i -N -H "Upgrade: websocket" -H "Connection: Upgrade" https://ws.example.com/ws,响应头中应含HTTP/1.1 101及正确 Upgrade 字段 - 检查 Nginx error.log,重点搜索
upstream sent no valid HTTP/1.0 header或client sent invalid upgrade request,这类日志通常指向 HTTP/2 干扰或 proxy_set_header 缺失
替代方案:TCP 层透传(适用于 TLS 终止前移)
若架构允许,可跳过 Nginx 的 HTTP 层解析,改用 stream 模块做纯 TCP 代理:
- 在 stream 上下文中监听 443 端口,不做 TLS 终止,直接转发到后端 WebSocket 服务
- 此时 WebSocket 握手全程由后端处理,Nginx 不参与协议协商,彻底规避 HTTP/2 兼容问题
- 代价是无法基于 HTTP 头做路由、限流或日志分析,适合对协议兼容性要求极高、且上层已有其他安全网关的场景

















