导读:本期聚焦于芒果创作的《Nginx反向代理WebSocket连接频繁断开怎么办?完整配置指南》,敬请观看详情。WebSocket长连接经过Nginx代理时经常出现自动断开、握手失败或者跨域报错,这类问题的根源大多在于Nginx默认配置并不支持协议升级。本文围绕Nginx代理WebSocket的核心要点展开,先讲清楚HTTP Upgrade机制为什么必须依赖Upgrade和Connection这两个请求头,再给出location块的完整可复制配置,包括proxy_set_header、超时参数以及map指令的动态写法,最后针对502、连接超时断开、wss证书等常见故障给出排查思路。看完这篇就能把Nginx的WebSocket代理稳定跑起来,长连接不再莫名掉线。

不少人在本地开发时WebSocket一切正常,应用一部署到线上、前面加了Nginx就立刻出问题:要么握手直接返回400,要么连接建立后几十秒到几分钟就莫名断开。这不是WebSocket本身的问题,而是Nginx作为反向代理时,默认行为并不支持HTTP协议升级到WebSocket协议,需要额外的配置才能让长连接顺利透传。本文把Nginx代理WebSocket的几个关键配置点逐一讲清楚,并附上可直接使用的完整配置。

Nginx反向代理WebSocket连接频繁断开怎么办?完整配置指南

为什么Nginx代理WebSocket需要特殊的Upgrade头

要理解配置为什么长那样,得先明白WebSocket的握手原理。WebSocket并不是一个独立于HTTP的新协议端口,它的握手阶段借用了HTTP/1.1的Upgrade机制:客户端先发一个普通的HTTP GET请求,但带上Upgrade: websocket和Connection: Upgrade这两个请求头,服务端如果支持,就返回101状态码,表示协议切换成功,之后这条TCP连接就不再走HTTP逻辑,而是由WebSocket协议全双工通信。

问题就出在这里。Nginx作为反向代理时,默认会把客户端请求转发给后端,但转发时会重写或丢弃Upgrade和Connection这两个头。后端收不到升级请求,自然不会返回101,客户端等不到协议切换就报错,这就是最常见的“本地能用、加了Nginx就400”的原因。

解决办法就是通过proxy_set_header把这两个头显式传给后端。同时,Nginx默认的代理是短连接思维,对已建立的双工长连接需要用proxy_http_version 1.1明确使用HTTP/1.1,因为HTTP/1.0并不支持Upgrade机制。这三个指令缺一不可,是WebSocket代理配置的基石。

location块的标准配置写法

下面是一份生产环境可直接使用的配置示例,假设WebSocket服务跑在后端8000端口:

location /ws/ {
    # 切换到HTTP/1.1,Upgrade机制只在这个版本可用
    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;

    # 后端WebSocket服务地址
    proxy_pass http://127.0.0.1:8000;
}

注意一个细节:Upgrade头的值用了变量$http_upgrade而不是写死为websocket。这样写的好处是,当同一个location既可能收到普通HTTP请求又可能收到WebSocket升级请求时,Nginx能根据客户端实际发来的头动态透传,兼容性更好。

如果不想为WebSocket单独划分location,也可以把这段头配置合并到通用的location /里。但要小心Connection头写死成"upgrade"后,普通HTTP请求的keep-alive行为会受影响,所以更优雅的方案是用map指令按需设置,下一节详细说。

用map动态处理Connection头

更规范的写法是在http块或server块里定义一个map,根据客户端是否携带Upgrade头来决定Connection的值:

# 放在http块中
map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

server {
    listen 80;
    server_name example.ipipp.com;

    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_read_timeout 300s;
        proxy_send_timeout 300s;
    }
}

map的逻辑很直白:客户端发了Upgrade头,$http_upgrade非空,Connection就设为upgrade;普通请求时Upgrade头为空,Connection设为close,不影响常规HTTP代理。这种写法是官方文档推荐的方式,适合WebSocket和普通接口共用一个域名的场景。

需要提醒的是,proxy_set_header有个继承特性:如果location里写了任何一条proxy_set_header,就会覆盖上层server或http块中的全部proxy_set_header,而不是合并。所以头配置要么集中写在location里,要么全写在server里,避免部分生效部分被覆盖导致排查困难。

长连接断开:超时参数才是元凶

很多配置正确的同学依然遇到“连上一段时间就掉线”,这几乎都是Nginx的默认超时在作怪。proxy_read_timeout默认只有60秒,含义是如果60秒内后端没有任何数据发往客户端,Nginx就主动关闭连接。聊天室这种低频消息场景,两次消息间隔很容易超过60秒,于是连接被Nginx悄悄掐断,客户端表现为1006异常关闭。

解决思路有两条。第一条是简单粗暴地把proxy_read_timeout调大,比如设为3600s甚至更长,配合proxy_send_timeout一起调整。这种方式配置最少,但依赖业务层的消息频率,如果真的一小时没有任何数据流动,连接还是会被关。

第二条是更工程化的做法:在应用层实现心跳机制,客户端每25到30秒发一次ping帧,服务端回pong。这样既能让Nginx的重置计时器不断刷新,也能及时检测出半开连接(比如客户端断网后TCP并没断)。实际上各类WebSocket库的心跳功能,很大程度上就是为了对抗中间代理的超时策略,建议无论如何都加上。

wss、502等常见问题排查

线上使用HTTPS站点时,前端必须用wss://协议而不是ws://,否则浏览器会因混合内容策略直接拒绝连接。Nginx侧不需要额外配置协议转换,只要WebSocket的location落在配置了SSL证书的server块里,Nginx会自动完成TLS卸载,后端依旧接收明文的WebSocket流量。

如果握手阶段就返回502,先检查后端服务是否真的在监听对应端口,用ss -tlnp | grep 8000确认。如果后端用的是Node.js的某些框架,还要确认它绑定的是0.0.0.0而不是127.0.0.1,以及Nginx所在机器能否访问到后端。另外,用了负载均衡(upstream)时,务必在upstream里配置ip_hash或开启后端会话保持,否则握手和后续请求被分到不同后端机器,连接会随机失败。

最后提一个容易忽略的点:如果Nginx前面还有CDN或者另一层代理,要确认那一层也支持并透传Upgrade头,任何一环卡住都会导致升级失败。排查时可以在客户端用浏览器开发者工具看101状态码是否返回,逐步定位断在哪一层。

总结一下核心要点:Upgrade和Connection两个头必须传、proxy_http_version必须是1.1、proxy_read_timeout要按业务调大并配合心跳、HTTPS下记得用wss协议。把这四点配置到位,Nginx代理WebSocket就能长期稳定运行。

Nginx反向代理WebSocketproxy_read_timeout修改时间:2026-09-10 01:04:46

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/0910/53710.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。