要让 proxy_set_header Upgrade 同时支持 HTTP 和 WebSocket,必须用 $http_upgrade 变量动态透传,并配合 map 指令设置 Connection 头,再启用 proxy_http_version 1.1、proxy_read_timeout 和 proxy_send_timeout。

要让 proxy_set_header Upgrade 同时支持普通 HTTP 请求和 WebSocket,关键不是“写死”某个值,而是动态传递客户端原始的 Upgrade 头,并配合 Connection 头的智能判断。Nginx 本身不拦截或修改 Upgrade,但默认不会透传它——必须显式配置,且方式要对,否则 HTTP 流量可能出问题,WebSocket 更是直接失败。
必须用 $http_upgrade 变量,不能写死 "websocket"
Nginx 提供的 $http_upgrade 是一个内置变量,它只在客户端请求中实际存在 Upgrade 头时才非空(比如值为 websocket),否则为空字符串。
这样做的好处是:
- WebSocket 客户端发
Upgrade: websocket→$http_upgrade值为websocket→ 正确转发 - 普通 HTTP 请求没带 Upgrade 头 →
$http_upgrade为空 → Nginx 不设置 Upgrade 头 → 后端收到干净的 HTTP 请求,不受干扰
如果写成 proxy_set_header Upgrade "websocket":
- WebSocket 连接看似能通,但遇到非标准客户端(如某些 IoT 设备用
Upgrade: h2c或自定义协议)会丢弃升级意图 - 更严重的是,部分后端框架看到非法 Upgrade 头可能直接拒收或记录告警,影响 HTTP 接口稳定性
Connection 头必须配合 map 规则,避免误关连接
Upgrade 和 Connection 是一对“搭档”。HTTP/1.1 协议规定:只有当 Upgrade 头存在时,Connection: upgrade 才有意义;否则应保持默认行为(如 keep-alive 或由后端决定)。
所以不能简单写:
proxy_set_header Connection "upgrade"; # ❌ 错误:所有请求都发 Connection: upgrade
而应使用 map 映射:
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}然后在 location 中写:
proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade;
这样:
- 客户端带
Upgrade: websocket→$http_upgrade非空 →$connection_upgrade=upgrade→ 触发协议升级 - 客户端无 Upgrade 头 →
$http_upgrade为空 →$connection_upgrade=close→ Nginx 发Connection: close,符合 HTTP/1.0 兼容逻辑,不影响后端正常处理
注意:
'' close中的单引号表示空字符串,不是引号字符本身。这个 map 必须放在 http 块顶层,不能嵌套在 server 或 location 里。
其他配套项不能省,否则 WebSocket 仍会断连
仅靠 Upgrade 和 Connection 不够,还需三项基础配置协同工作:
-
proxy_http_version 1.1;—— WebSocket 握手强制要求 HTTP/1.1,设成 1.0 会导致后端收不到 Upgrade -
proxy_read_timeout 86400;—— 默认 60 秒,WebSocket 空闲时会被 Nginx 主动断开,设大值(如 24 小时)或 0(不限制) -
proxy_send_timeout 86400;—— 防止后端响应间隔稍长就被切断
这些对 HTTP 业务无副作用,只是延长了代理层的等待窗口,实际连接生命周期仍由后端控制。
不复杂但容易忽略


















