Nginx 配置导致 “无法建立到 ws://xxx/_stcore/stream 的连接” 的解决方案
今天部署了个 web 服务,老实说我一开始没意识到它用了 WebSocket。反正按流程部署,IP 能正常访问,Nginx 代理访问页面空白,F12 一看才发现控制台报错:
Firefox 无法建立到 ws://abc.com/_stcore/stream 服务器的连接。 main.ac67fab5.js:2:4683309
加载页面时与 ws://abc.com/_stcore/stream 的连接中断。 main.ac67fab5.js:2:4683309
... ...
从已有信息来看,估计是 WebSocket 链接挂了,那就是 Nginx 转发过程中出的问题。
网上查了下,以下是大致原理和解决方案。
工作原理
WebSocket 是如何工作的?
WebSocket 起初看似普通 HTTP 请求(客户端发出 HTTP 握手),但需要通过一个 Upgrade
头进行 协议升级。升级成功后,连接会变成一个持久化的“全双工”通道。
然而——Nginx 默认不会转发这个升级请求,后端压根不知道客户端要干啥,自然响应失败。
类比解释:快递换电话?
想象你是客户端,打电话给 Nginx:“我想和后端视频通话(WebSocket)。”
Nginx 拿起听筒,却转头告诉后端:“有人找你,普通电话(HTTP)。”
后端一脸懵:“我只支持视频通话啊……”于是通话立马被挂断。
解决方法
原 Nginx 配置:
server {listen 80;server_name abc.com;location / {proxy_pass http://ip地址:900;proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;}
}
修改后 Nginx 配置(已标注关键改动):
server {listen 80;server_name abc.com;location / {proxy_pass http://ip地址:900;proxy_http_version 1.1; # ✅ 强制使用 HTTP/1.1proxy_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-Proto $scheme; # 🌟 协议类型信息# ⏱️ 长连接保活(防止误断)proxy_read_timeout 86400s;proxy_send_timeout 86400s;}
}
nginx 服务 reload 后 web 访问正常,报错也消失了。
参数一览说明
配置项 说明 是否必须 proxy_http_version 1.1
开启 HTTP/1.1,支持持久连接 ✅ 必需 Upgrade $http_upgrade
保留客户端的协议升级请求 ✅ 必需 Connection "upgrade"
告知后端要升级协议 ✅ 必需 proxy_read_timeout
避免 WebSocket 被误判超时断开 ✅ 强烈建议
看这个图就明白了:
graph LR
A[客户端] -->|1. 发起握手(带Upgrade头)| B(Nginx)
B -->|2. 默认未转发头信息| C[后端服务]
C -->|3. 无法识别升级请求| D[连接失败 ❌]
B -->|✅ 配置后转发 Upgrade 信息| E[后端服务]
E -->|4. 返回 101 状态码| F[WebSocket 建立成功 ✅]
优化建议
1、WebSocket 独立路径隔离
避免混用请求路径,建议单独为 WebSocket 定义 location
:
location /_stcore/ {proxy_pass http://backend;proxy_http_version 1.1;proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection "upgrade";...
}
2、负载均衡:高可用转发
为后端部署多个节点,保持会话一致性:
upstream websocket_backend {server 10.0.0.1:9000;server 10.0.0.2:9000;ip_hash; # 粘性会话
}
3、启用加密通信(WSS)
WebSocket 明文传输风险极高,生产环境必须走 wss://
:
listen 443 ssl;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
总结
一句话:Nginx 是默认“不会翻译 WebSocket 请求”的 HTTP 代理,需要你手动告诉它如何升级协议。