spring cloud gateway 默认不自动代理 websocket 请求,必须显式配置 ws:// 或 lb:ws:// 协议前缀路由,并透传 upgrade 和 connection 头,否则握手失败导致 400 或连接立即关闭;网关仅负责连接转发,不解析消息内容,也不支持 sticky session。
spring cloud gateway 默认不自动代理 websocket 请求,必须显式配置路由 + 启用升级头,否则 400 或连接立即关闭。
WebSocket 路由必须用 ws:// 或 lb:ws:// 协议前缀
Gateway 识别 WebSocket 流量依赖 URI 协议类型,不是靠路径后缀或 Header 判断。写成 http:// 或直接服务名(如 websocket-service)会导致降级为普通 HTTP 代理,握手失败。
-
uri: ws://backend-service:8080:直连单实例,适合开发或无注册中心场景 -
uri: lb:ws://websocket-service:走负载均衡,要求服务已注册到 Nacos/Eureka,且 Gateway 已启用spring-cloud-starter-loadbalancer - 绝对不要写
uri: http://...或uri: websocket-service—— 这两类配置看似能启动,但实际无法完成 WebSocket Upgrade
Upgrade 和 Connection 头必须透传
客户端发起的 WebSocket 握手请求含关键 Header:Upgrade: websocket、Connection: Upgrade。Gateway 默认会过滤掉这些头,导致后端收不到升级信号,返回 400 或直接关闭连接。
- 在路由配置中显式添加
filters透传:
spring:
cloud:
gateway:
routes:
- id: ws_route
uri: lb:ws://system-service
predicates:
- Path=/ws/**
filters:
- RewritePath=/ws/(?<segment>.*), /$\{segment}
- SetRequestHeader=Connection, "Upgrade"
- SetRequestHeader=Upgrade, websocket</segment>
-
SetRequestHeader必须写全,大小写敏感;值带英文双引号是 YAML 规范要求 - 若后端是若依的
@ServerEndpoint("/ws/{userId}"),还需配合RewritePath去掉网关层路径前缀,否则后端匹配不到端点
网关层不能做 WebSocket 消息内容路由
Spring Cloud Gateway 的 WebSocketRoutingFilter 只负责连接建立和帧转发,不解析消息体。它无法根据 JSON 内容里的 "type": "chat" 把消息分发到不同微服务 —— 这类逻辑必须由后端业务服务自己实现。
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
- 网关只管“把 TCP 连接转给哪个服务实例”,不管“这个连接里发来的某条消息该进哪个 handler”
- 若需多路径分发(如
/ws/chat、/ws/notify),应在后端统一暴露一个 WebSocket 端点,再用websockets库的router或 Spring 的@MessageMapping做二级路由 - 网关做路径级路由(如不同 path 对应不同后端服务)可行,但每个 path 需独立配置路由项,且后端必须各自实现完整 WebSocket 协议栈
Nacos 动态刷新 WebSocket 路由有延迟
通过 Nacos 配置中心推送 Gateway 路由变更时,WebSocket 连接不会自动迁移。已建立的连接仍绑定在旧实例上,新连接才会走新路由。
- 这意味着滚动发布 WebSocket 后端服务时,会出现新老连接并存的情况,状态不一致风险高
- 若依赖会话广播(如用户上线通知),必须额外引入 Redis Pub/Sub 或事件总线,在服务实例间同步连接状态
- 网关本身不维护 WebSocket 连接状态表,也不支持 sticky session —— 这个责任完全落在后端服务的会话管理设计上
真正难的从来不是配通那条连接,而是当 5000 个用户同时在线、三个实例滚动重启、某台机器网络抖动时,怎么让每条消息都落到正确的 Session 里,且不丢不重。这部分没标准答案,得看你的会话 ID 怎么生成、心跳怎么保活、断线重连怎么设计。










