关键在于用map指令动态设置Connection头:当$http_upgrade存在时设为upgrade,为空时设为close,再配合proxy_http_version 1.1、proxy_set_header Upgrade $http_upgrade和proxy_set_header Connection $connection_upgrade三要素,确保仅WebSocket请求升级、普通HTTP请求不误触发。

要让 Nginx 正确代理 WebSocket 请求,关键不是简单写死 Connection: upgrade,而是根据客户端是否真发起升级请求,动态决定 Connection 头的值——这正是 map 指令的核心作用。
为什么必须用 map 而不能直接写死 Connection 头
WebSocket 握手依赖两个头部协同工作:Upgrade: websocket 和 Connection: upgrade。但普通 HTTP 请求也带 Connection 头(如 keep-alive 或 close)。如果在 location 里硬写:
proxy_set_header Connection "upgrade";
会导致所有请求都被标记为升级,后端对非 WebSocket 请求返回 400 或意外关闭连接。
map 的价值在于:只在真正需要升级时才设 upgrade,其余情况设 close,完全匹配协议语义。
map 指令的标准写法与原理
把这段配置放在 http 块顶层(不能放在 server 或 location 内):
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
它的逻辑是:
-
$http_upgrade是 Nginx 自动提取的请求头值(如websocket) - 只要该头存在且非空,
$connection_upgrade就被赋值为upgrade - 如果请求没带 Upgrade 头(即值为空字符串
''),就赋值为close
location 中配套使用的三要素
仅定义 map 不够,必须在对应 location 里配合使用:
-
proxy_http_version 1.1;—— HTTP/1.0 不支持 Upgrade,必须显式启用 1.1 -
proxy_set_header Upgrade $http_upgrade;—— 把原始 Upgrade 头原样传给后端 -
proxy_set_header Connection $connection_upgrade;—— 使用 map 生成的动态值
这三行缺一不可,顺序无关,但必须共存于同一 location 块中。
别忘了配套调优项
WebSocket 是长连接,Nginx 默认配置会破坏它:
-
proxy_read_timeout 3600;—— 防止空闲连接被主动断开(按业务最长等待时间设) -
proxy_send_timeout 3600;—— 同上,保障服务端推送不超时 -
proxy_buffering off;—— 关闭缓冲,避免消息堆积延迟 -
proxy_cache_bypass $http_upgrade;—— 确保 Upgrade 请求不走缓存
这些设置虽不直接参与 Connection 头动态升级,却是 WebSocket 稳定运行的实际支撑。


















