要真正支持websocket长连接,必须透传upgrade和connection头、关闭proxy_buffering、设proxy_read_timeout和proxy_send_timeout为86400、启用tcp_nodelay on,并禁用proxy_cache;关键在于确保协议升级不被截断、连接不被超时中断、帧流不被缓冲干扰。

要在 Nginx 反向代理中真正支持 WebSocket 长连接,不能只写 proxy_pass 就完事。核心是让握手成功、连接不被中断、帧流不被干扰——这需要同时满足协议升级、连接保持和行为适配三个层面。
必须透传升级请求头
WebSocket 握手依赖两个逐跳(hop-by-hop)HTTP 头,Nginx 默认会丢弃它们,导致后端收不到升级意图,返回 400 或直接降级为普通 HTTP:
- proxy_http_version 1.1; —— HTTP/1.0 不支持 Upgrade,缺了这句握手必败
-
proxy_set_header Upgrade $http_upgrade; —— 使用内置变量
$http_upgrade,大小写敏感,不能写成$upgrade或硬编码"websocket" -
proxy_set_header Connection "upgrade"; —— 值必须是带英文双引号的字符串
"upgrade",不是$http_connection(它可能是keep-alive)
必须延长超时并关闭缓冲
WebSocket 是全双工长连接,Nginx 默认策略全是“反长连接”的,空闲几十秒就断开,或缓存帧造成粘包:
- proxy_read_timeout 86400; 和 proxy_send_timeout 86400; —— 设为 24 小时,避免空闲期被静默关闭;若后端有 30 秒心跳,可设为 45,但绝不可 ≤30
- proxy_buffering off; —— 关闭响应缓冲,防止多个 TEXT/BINARY 帧被合并转发
- tcp_nodelay on; —— 绕过 Nagle 算法,小数据(如光标移动、按键)立即送达
必须避开常见陷阱
很多看似合理配置,实际会让连接变得不可靠:
- 不启用任何
proxy_cache_*指令 —— WebSocket 消息不可缓存,启用即失败 - 不加
add_header Access-Control-Allow-Origin "*"—— 跨域由后端在 101 响应中返回 CORS 头,Nginx 只需透传,加了反而可能覆盖 - location 路径要精准匹配 WebSocket 入口(如
/ws/、/socket.io/或/),避免被其他正则规则截断
进阶建议:用 map 动态控制 Connection 头
更稳妥的做法是配合 map 指令,区分普通请求和升级请求:
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
然后在 location 中写:
proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade;
这样当客户端没发 Upgrade 头(比如普通 GET 请求),Nginx 就不会错误地发起隧道化,提升兼容性。











