Nginx 代理 WebSocket:协议升级、空闲断开与连接验证
WebSocket 先通过 HTTP 建立连接,再升级为双向消息通道。因此,普通页面代理成功并不代表实时连接配置完整。本文适用于使用 HTTP/1.1 升级流程的 WebSocket 应用和受维护的 Nginx,假设应用本机监听 8000 端口。
先确认握手路径和应用要求
查清应用实际使用 /ws/、其他路径还是带查询参数的入口,并确认认证方式、允许的来源和子协议。不要拿普通首页作为 WebSocket 测试地址;应用必须主动接受协议升级,代理不能把普通 HTTP 服务变成 WebSocket 服务。
如果只有外部连接失败,先比较应用本地测试与经过 Nginx 的结果。记录握手状态码、应用日志和浏览器控制台信息,区分未找到路径、未通过认证、来源被拒绝以及代理根本未转发升级请求。
在正确上下文传递升级信息
Upgrade 和 Connection 属于需要明确处理的连接相关头。下面的 map 放在 http 上下文,location 放在已经配置好域名和 HTTPS 的目标站点内:
# http 上下文
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
# 目标 server 上下文
location /ws/ {
proxy_pass http://127.0.0.1:8000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
proxy_read_timeout 75s;
}
该写法保留 /ws/ 路径,适用于后端也使用这一入口的情况。地址、路径与超时值都是示例,不能直接覆盖已有同名 location。升级机制可参考Nginx WebSocket 文档。
区分握手成功与消息通道正常
浏览器通常应看到成功的协议升级响应,但这只说明握手成立。继续用应用认可的测试账号发送一条无副作用的消息,检查服务端接收、客户端回传、订阅和取消订阅是否正常。
握手返回 401 或 403 时,应检查认证与来源策略;返回 404 时,优先核对路径是否被代理改写;连接立即关闭时,查看应用是否拒绝子协议或初始化消息。不要通过关闭鉴权、放开所有来源来证明通道可用。
网站通过 HTTPS 提供服务时,客户端应使用对应的安全 WebSocket 入口。CDN 或负载均衡也需要支持该通道;边缘到源站的配置必须一起检查,不能只测试浏览器到边缘的一段。
空闲断开需要协调心跳与超时
代理读取超时关注相邻上游读取之间的空闲等待,不等于连接从建立开始只能存在固定时长。示例中的七十五秒只是演示值,实际应结合应用心跳和前置网关限制设计。Nginx 代理超时说明
如果应用长时间没有消息,可以由应用支持的心跳机制保持状态并识别失联,但不能无限提高超时掩盖没有重连逻辑的问题。客户端重连时还应处理重复订阅、消息补发与状态恢复,避免每次断开都重复执行业务。
同时关注连接数、内存和文件描述符使用。大量空闲连接也是资源负载,不能根据普通页面每秒请求数直接推导 WebSocket 容量。容量测试应在授权环境和可控范围内进行。
用真实断开场景完成验收
修改前备份配置,语法检查通过后重新加载,再验证连接、空闲等待、主动退出和网络短暂中断。测试应用重启后客户端能否恢复,并检查是否产生重复会话或持续重试风暴。
若本次配置引入异常,恢复原站点配置并重新验证,不要同时修改代理、应用心跳和客户端重试多个变量。保存握手路径、认证要求、心跳周期与各层超时的记录,之后增加 CDN 或迁移应用时就能逐项核对。