WebSocket连接报404主因是Nginx未正确透传升级请求,需配置proxy_http_version 1.1、Upgrade头和Connection头,并确保location路径斜杠一致、timeout设置合理。

WebSocket 连接报 404,不是后端服务没起来,也不是路径写错了——大概率是 Nginx 没把升级请求“传到位”。只要补全三样东西:proxy_http_version 1.1、Upgrade 头、Connection 头,90% 的 404 就会消失。
location 路径末尾斜杠不匹配导致 404
路径配置里少一个 /,就会让 Nginx 错误重写 URI,后端根本收不到原始的 WebSocket 升级请求。比如前端连 ws://example.com/wss/echo,但配置写成:
location /wss { proxy_pass http://127.0.0.1:8080; }
这时 Nginx 会把 /wss/echo 剪掉前缀 /wss,转发成 /echo 给后端;而如果后端只监听 /wss/echo 或根路径下无路由,就直接返回 404。
正确做法是保持前后斜杠一致:
-
location /wss/必须配proxy_pass http://127.0.0.1:8080/(结尾都有/) - 或者用精确匹配:
location = /wss+proxy_pass http://127.0.0.1:8080/wss - 用
curl -v ws://example.com/wss/观察实际发给后端的GET路径和Host头,比猜更可靠
缺少 Upgrade 和 Connection 请求头
WebSocket 握手本质是一个带特殊头的 HTTP 请求,Nginx 默认不转发 Upgrade 和 Connection,后端收不到升级意图,就当普通 HTTP 处理,自然返回 404。
必须在对应 location 块中显式添加:
-
proxy_http_version 1.1(HTTP/1.0 不支持升级机制) -
proxy_set_header Upgrade $http_upgrade(把客户端的Upgrade: websocket原样传过去) -
proxy_set_header Connection "upgrade"(注意引号,值必须是upgrade字面量)
漏掉任意一项,握手都会失败。别信“我加了两个,应该够了”——三个是一套动作,缺一不可。
map 指令未定义导致 Connection 头失效
如果你把 proxy_set_header Connection "upgrade" 换成了 proxy_set_header Connection $connection_upgrade,那必须提前在 http 块里声明 map:
map $http_upgrade $connection_upgrade { default upgrade; '' close; }
否则 Nginx 启动会报错,或者 $connection_upgrade 展开为空,最终发给后端的是 Connection: (空值),等价于没传头。
简单场景直接写死 "upgrade" 更稳妥;只有需要兼容非 WebSocket 请求(比如同时代理 HTTP 和 WS)时,才用 map 动态判断。
proxy_read_timeout 过短引发连接被主动关闭
WebSocket 是长连接,但 Nginx 默认 60 秒无数据就断开。如果后端没发 ping 帧,或心跳间隔 >60 秒,连接会在握手成功后静默断开,浏览器可能显示为“已连接但收不到消息”,甚至某些情况回落为 404(取决于后端行为)。
建议显式延长超时:
-
proxy_read_timeout 7200(2 小时,足够覆盖大多数心跳策略) -
proxy_send_timeout 7200(避免发送延迟触发中断) - 不要依赖默认值,尤其在 IoT、监控类长周期连接场景
真正容易被忽略的是:这些 timeout 必须放在和 proxy_pass 同一级的 location 块里,写在 server 或 http 级可能不生效。


















