Nginx 不解决 WebSocket 跨域逻辑,而是透传 Upgrade 请求、维持长连接并配合后端完成 Origin 校验;关键配置包括 proxy_http_version 1.1、proxy_set_header Upgrade $http_upgrade、proxy_set_header Connection "upgrade",以及关闭缓冲和延长超时。

必须配置的三项协议升级指令
缺一不可,否则握手直接失败(常见报错:`net::ERR_CONNECTION_RESET` 或 `400 Bad Request`):
- proxy_http_version 1.1; —— WebSocket 升级依赖 HTTP/1.1 的持久连接能力,HTTP/1.0 不支持
- proxy_set_header Upgrade $http_upgrade; —— 将客户端原始的 `Upgrade: websocket` 头传给后端(注意变量名是 `$http_upgrade`,不是 `$upgrade`)
- proxy_set_header Connection "upgrade"; —— 强制设为 `"upgrade"` 字符串,覆盖 Nginx 默认的 `Connection: close`,告诉后端这是升级请求
必须关闭缓冲与缩短超时干扰
WebSocket 是全双工长连接,Nginx 默认行为会主动中断它:
- proxy_buffering off; —— 关闭响应缓冲,避免 Upgrade 响应被暂存导致握手延迟或失败
- proxy_read_timeout 86400; —— 设为大值(如 24 小时),防止空闲时 Nginx 主动断连
- proxy_send_timeout 86400; —— 同样设大,保障服务端心跳或消息能及时发出
- 禁用 proxy_cache 相关指令 —— WebSocket 消息不可缓存,开启会导致不可预知错误
跨域头交给后端返回,Nginx 不应重复添加
WebSocket 握手成功后返回的是 HTTP 101 状态码,此时服务端可在响应头中返回 `Access-Control-Allow-Origin` 等头(用于后续 fetch/XHR 等请求,非 WebSocket 本身必需)。Nginx 默认会透传这些头,无需干预:
- 不要在 Nginx 的 `location /ws` 块里写 `add_header Access-Control-Allow-Origin "*";` —— 这对 WebSocket 握手无效,还可能覆盖后端返回的精确 Origin 校验结果
- 若后端已返回 `Access-Control-Allow-Credentials: true`,Nginx 会原样透传;前端需确保 `new WebSocket()` 连接时没带凭据(wss 协议下默认不带 cookie),否则需后端严格匹配 Origin
- 如需支持多域名白名单,应在后端根据 `Origin` 请求头动态判断并设置响应头,Nginx 层仅负责透传
典型 location 配置示例(精简可用)
假设前端访问 wss://app.example.com/ws,后端 WebSocket 服务运行在 http://127.0.0.1:3000/ws
location /ws {
proxy_pass http://127.0.0.1:3000/ws;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header 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;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
proxy_read_timeout 86400;
proxy_send_timeout 86400;
}
验证时打开浏览器开发者工具 Network 面板,找到 WebSocket 请求,确认状态码为 101,且 Response Headers 中包含 `Upgrade: websocket` 和 `Connection: upgrade` —— 这表示握手已由 Nginx 成功透传并被后端接受。


















