Nginx 配置导致 “无法建立到 ws://xxx/_stcore/stream 的连接” 的解决方案

发布于:2025-08-02 ⋅ 阅读:(16) ⋅ 点赞:(0)

今天部署了个 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.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-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 代理,需要你手动告诉它如何升级协议。


网站公告

今日签到

点亮在社区的每一天
去签到