ingress-nginx默认proxy-read-timeout和proxy-send-timeout为60秒,websocket长连接因空闲超时被静默关闭,需显式配置超时参数、upgrade/connection头透传及websocket-services注解,并确保ingressclassname匹配、tls终止在ingress侧且路径精确匹配。

ingress-nginx 默认不自动启用 WebSocket 支持,必须显式配置超时和协议识别,否则连接会在 60 秒左右被静默关闭。
为什么 WebSocket 连接会断开?
根本原因是 ingress-nginx 的默认代理超时(proxy-read-timeout 和 proxy-send-timeout)为 60 秒,而 WebSocket 是长连接,需要保持活跃状态。Nginx 在超时后会主动关闭上游连接,客户端收到 1006 错误或直接断连。
- 浏览器控制台常见报错:
WebSocket is closed before the connection is established或Failed to execute 'send' on 'WebSocket': Still in CONNECTING state - 服务端日志可能无错误,但连接频繁重建
- 仅靠
Upgrade: websocket请求头不足以触发 Nginx 的 WebSocket 模式,必须配合注解和超时设置
nginx.ingress.kubernetes.io/websocket-services 注解是否必须?
不是必须,但强烈建议加上——尤其当你的 Ingress 控制器版本 ≤ v1.7.x。这个注解会强制 Nginx 将匹配路径的请求识别为 WebSocket 流量,并启用对应优化逻辑(如禁用缓冲、调整连接复用策略)。
- 新版(v1.8+)中该注解已软弃用,但仍向后兼容;若不加,依赖
Upgrade+Connection: upgrade头也能工作,但稳定性略低 - 值必须是 Service 名称(如
websocket-server),不能带命名空间前缀 - 多个服务用逗号分隔:
nginx.ingress.kubernetes.io/websocket-services: "ws-a,ws-b"
关键超时参数怎么设才合理?
三个超时参数必须同时调大,且 proxy-read-timeout 和 proxy-send-timeout 应一致(通常设为 3600),否则单向空闲会先触发断连。
-
nginx.ingress.kubernetes.io/proxy-connect-timeout: "30":建立上游连接的上限,保持默认即可 -
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600":从上游读数据的最大等待时间,WebSocket 心跳间隔应小于该值 -
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600":向下游发送响应的最大等待时间,影响客户端接收延迟 - 额外可选:
nginx.ingress.kubernetes.io/upstream-keepalive-timeout: "3600",避免上游连接池过早回收长连接
路径匹配和 TLS 配置要注意什么?
WebSocket 协议升级必须发生在 HTTP/HTTPS 层,所以路径必须能被 Ingress 正确路由,且 TLS 终止点必须在 ingress-nginx 侧(而非云厂商 LB 层)。
- 路径建议用精确前缀(
pathType: Prefix)并以/ws或/api/ws等清晰路径开头,避免与 REST 路由冲突 - 如果前端用
wss://,Ingress 必须绑定有效 TLS 证书;自签名证书会导致浏览器拒绝 WebSocket 升级 - 不要在云厂商 SLB 层终止 TLS 后再透传到 ingress-nginx —— 这会导致
Upgrade头丢失,Nginx 无法识别 WebSocket - 确认 Service 的
targetPort与后端 Pod 实际监听端口一致(如 Node.js 的server.listen(3000),则targetPort: 3000)
ingressClassName 字段必须与集群中实际运行的 Ingress Controller 的 ingressClass 名称完全一致。很多断连问题最终都卡在这一步——你改了 Ingress 配置,但控制器压根没监听它。











