在 linux 中结构化配置 nginx 以支持 websocket 协议升级,核心在于利用 `map` 指令构建 http 连接升级的映射表,并在 `location` 块中通过 `proxy_set_header` 将升级请求透传给后端服务。具体做法是定义一个名为 `$connection_upgrade` 的变量,根据客户端发送的 `upgrade` 头部动态匹配值,随后在代理配置中将该变量赋值给 `upgrade` 和 `connection` 请求头,同时必须设置 `proxy_http_version 1.1` 以启用长连接特性。

如何定义连接升级的映射规则
要正确识别 WebSocket 升级请求,需要在 `http` 上下文中使用 `map` 指令创建一个变量映射。该指令检查客户端请求中的 `Upgrade` 头部字段,如果包含 "websocket"(不区分大小写),则将自定义变量 `$connection_upgrade` 设置为 "upgrade",否则设置为 "close"。这种结构化的映射方式避免了在多个 location 中重复编写复杂的正则表达式判断逻辑,使得配置更加清晰且易于维护。

http {
# 定义连接升级映射
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 80;
server_name example.com;
location /ws/ {
proxy_pass http://backend_server;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
}
}
如何在 Location 块中透传升级头部
在确定了映射规则后,具体的 `location` 配置负责将 WebSocket 握手信息传递给后端应用服务器。关键在于设置 `proxy_http_version` 为 `1.1`,因为 WebSocket 协议基于 HTTP/1.1 的扩展,默认情况下 Nginx 可能使用 HTTP/1.0 进行代理,这会导致握手失败。接着,通过 `proxy_set_header` 指令,分别将原始的 `Upgrade` 头部和刚才定义的 `$connection_upgrade` 变量值赋给新的请求头,确保后端能接收到正确的升级信号并保持连接状态。

# 假设后端运行在 localhost:8080
upstream websocket_backend {
server 127.0.0.1:8080;
}
server {
listen 443 ssl;
server_name wss.example.com;
# SSL 配置省略...
location /chat {
proxy_pass http://websocket_backend;
# 必须指定 HTTP/1.1
proxy_http_version 1.1;
# 透传升级头部
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
# 保持其他必要头部
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
当 Upgrade 头部为空时连接状态如何处理
基于上述程序配置,当客户端发起普通 HTTP 请求而非 WebSocket 升级请求时,`$http_upgrade` 变量为空字符串。此时,`map` 指令会将 `$connection_upgrade` 映射为 "close"。Nginx 会将 `Connection` 头部设置为 "close",这意味着代理连接在完成当前请求后将会关闭,而不是维持长连接。这种行为符合 HTTP/1.1 规范中对非升级请求的处理预期,确保了普通网页请求不会错误地占用 WebSocket 长连接资源,同时也验证了映射规则在不同输入条件下的正确分支逻辑。











