Nginx 不参与 WebSocket 子协议协商,仅透传 Sec-WebSocket-Protocol 头;必须配置 proxy_set_header Upgrade $http_upgrade、proxy_set_header Connection "upgrade" 和 proxy_http_version 1.1,且需确保中间链路不过滤该头,后端须严格匹配并返回一致协议名。

Nginx 本身不参与子协议协商逻辑,只负责透传 Sec-WebSocket-Protocol 请求头和响应头。只要配置正确,客户端与后端之间的子协议(如 json-rpc、chat.v1)就能完整协商成功。
必须启用的透传配置
子协议协商依赖原始握手头不被过滤或改写,以下三项是硬性要求:
-
proxy_set_header Upgrade $http_upgrade:Nginx 内置变量自动捕获客户端的
Upgrade和关联头(含Sec-WebSocket-Protocol),不能写死为"websocket" -
proxy_set_header Connection "upgrade":注意是固定字符串
"upgrade",不是$connection_upgrade(后者在非升级请求时为空,会导致Connection: close) - proxy_http_version 1.1:HTTP/1.0 不支持 Upgrade 机制,必须显式声明
不需要额外配置子协议名
Nginx 不解析、不校验、不匹配子协议名,也不做默认 fallback。例如:
- 客户端发起连接时带
Sec-WebSocket-Protocol: graphql-ws, json-rpc,Nginx 原样转发 - 后端若支持
graphql-ws,就在 101 响应中返回Sec-WebSocket-Protocol: graphql-ws,Nginx 同样原样透传回浏览器 - 若后端未返回该头,或返回值不在客户端列表中(大小写/符号不一致也算失败),浏览器会设
ws.protocol = "",但连接仍可建立
常见干扰点排查
子协议协商失败,90% 以上不是 Nginx 不支持,而是被意外阻断:
- CDN、WAF 或中间网关过滤了
Sec-WebSocket-Protocol头 - Nginx 配置漏掉
proxy_set_header Upgrade $http_upgrade,导致该头根本未发往后端 - 后端服务未显式调用
accept(subprotocol="xxx")(如 Pythonwebsockets库)或未实现协议匹配回调 - 浏览器开发者工具中检查 WS 连接的 Response Headers,确认是否包含且值完全匹配客户端所列之一
HTTPS(wss)场景补充
代理 wss:// 时,还需确保:
-
proxy_set_header X-Forwarded-Proto $scheme:让后端知道原始是 HTTPS,避免生成错误的
http://回调链接 - SSL 证书、
listen 443 ssl等基础 HTTPS 配置已就绪 - Nginx 解密 wss 流量后,以普通 ws 协议转发给后端,后端无需再处理 TLS


















