Nginx 代理 WebSocket:协议升级、空闲断开与连接验证

WebSocket 先通过 HTTP 建立连接,再升级为双向消息通道。因此,普通页面代理成功并不代表实时连接配置完整。本文适用于使用 HTTP/1.1 升级流程的 WebSocket 应用和受维护的 Nginx,假设应用本机监听 8000 端口。

先确认握手路径和应用要求

查清应用实际使用 /ws/、其他路径还是带查询参数的入口,并确认认证方式、允许的来源和子协议。不要拿普通首页作为 WebSocket 测试地址;应用必须主动接受协议升级,代理不能把普通 HTTP 服务变成 WebSocket 服务。

如果只有外部连接失败,先比较应用本地测试与经过 Nginx 的结果。记录握手状态码、应用日志和浏览器控制台信息,区分未找到路径、未通过认证、来源被拒绝以及代理根本未转发升级请求。

在正确上下文传递升级信息

UpgradeConnection 属于需要明确处理的连接相关头。下面的 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 或迁移应用时就能逐项核对。

参考资料

继续阅读

返回天理云文章中心

分享到:
上一篇
301、302 和 308 怎么选?网站重定向与请求方法的区别
下一篇
Nginx gzip 压缩怎么开?文本类型、CPU 开销与缓存验证
服务中心
企微客服
企微客服
给您高效服务
评价
您对当前页面的整体感受是否满意?
😞
非常不满意
😕
不满意
😐
一般
🙂
满意
😊
非常满意