nginx 仅透传 websocket 握手请求,不处理跨域逻辑;需配置 proxy_http_version 1.1、proxy_set_header upgrade $http_upgrade 和 connection "upgrade",关闭缓冲、延长超时,并禁用缓存,跨域头由后端精确返回。

Nginx 本身不解决 WebSocket 的跨域逻辑,它只负责正确透传握手请求,让后端能拿到原始 Origin 并完成校验。真正决定是否允许连接的是后端服务,Nginx 的作用是避免在代理环节破坏协议升级过程。
必须透传的三项升级头
WebSocket 握手依赖 HTTP/1.1 的 Upgrade 机制,缺一不可:
- proxy_http_version 1.1:HTTP/1.0 不支持持久连接和协议升级,必须显式启用
-
proxy_set_header Upgrade $http_upgrade:变量名是
$http_upgrade(带http_前缀),不是$upgrade;大小写敏感,必须原样转发客户端的Upgrade: websocket -
proxy_set_header Connection "upgrade":强制设为字符串
"upgrade",覆盖 Nginx 默认的Connection: close,否则后端收不到升级意图
关闭缓冲与延长超时
WebSocket 是长连接,Nginx 默认行为会主动中断:
- proxy_buffering off:防止 Upgrade 响应被缓存延迟,导致握手失败或超时
- proxy_read_timeout 86400 和 proxy_send_timeout 86400:设为大值(如 24 小时),避免空闲时被 Nginx 断连
- 禁用 proxy_cache 相关指令:WebSocket 帧不可缓存,开启会导致连接异常或消息丢失
跨域头由后端返回,Nginx 不干预
浏览器只在 HTTP 握手阶段检查 Origin,并依赖后端在 101 Switching Protocols 响应中返回合法 CORS 头:
-
不要在 Nginx 的 location 块里写
add_header Access-Control-Allow-Origin "*":101 响应不属于 2xx,默认不触发add_header;即使加了always,也可能覆盖后端精确匹配的 Origin 校验结果 -
后端需返回完整响应头:包括
Access-Control-Allow-Origin(必须精确匹配,不能为*若启用了 credentials)、Access-Control-Allow-Credentials: true、必要时还有Access-Control-Allow-Headers - Nginx 默认透传这些头:只要后端写了,Nginx 就会原样转发,无需额外配置
避免常见干扰项
一些看似合理但实际有害的操作:
-
不要用
if ($request_method = 'OPTIONS')拦截预检:WebSocket 握手没有 OPTIONS 预检,该写法易导致请求被错误拦截或降级 - 确保前端使用 wss://(非 ws://)访问 HTTPS 页面:混合内容会被现代浏览器直接阻止,连接卡在 pending 后失败
-
确认后端监听地址与 proxy_pass 一致:比如后端跑在
http://127.0.0.1:8080/ws,Nginx 的proxy_pass就不能漏掉/ws路径,否则路径错位导致 404 或 403











