—— 为什么你本地能流,一上网关就“卡死”

一、背景:SSE 本地好好的,上了 Gateway 全废了

在做 AI 问答流式输出时,我最初的架构是这样的:

Browser
  ↓
Spring Cloud Gateway
  ↓
AI Service(SSE)

现象非常诡异:

  • 直连 AI 服务:✅ 一边生成一边返回

  • 走 Gateway:❌ 页面一直 loading

  • 最后一次性返回,或者直接超时

当时的第一反应是:

“是不是 SSE 不能过网关?”

结论是:

SSE 可以过 Gateway,但默认配置下,几乎一定会翻车


二、SSE 在 Gateway 场景下到底“特殊”在哪?

1️⃣ SSE 的几个关键特性

  • 长连接

  • 响应体是持续写入

  • 没有 Content-Length

  • 依赖 Transfer-Encoding: chunked

而 Gateway 的本质是:

一个“智能代理” + 各种 Filter

这就产生了天然冲突。


三、第一个坑:响应被 Gateway “缓存”了

❌ 错误表现

  • AI 服务已经在流式返回

  • Gateway 一直等

  • 最后一次性吐给客户端

❌ 根本原因

Gateway 默认会尝试:

  • 聚合 response body

  • 处理后再返回

  • 破坏了 SSE 的“边写边发”


✅ 正确做法:禁止响应缓存

spring:
  cloud:
    gateway:
      httpclient:
        response-timeout: 0s

并且不要使用这些 Filter

  • ModifyResponseBody

  • RewriteResponseBody

  • CacheRequestBody

👉 这些 Filter 天生会吃掉流


四、第二个坑:超时设置会“悄悄杀死连接”

❌ 常见错误配置

spring:
  cloud:
    gateway:
      httpclient:
        connect-timeout: 5000
        response-timeout: 30s

对普通接口没问题
对 SSE 来说是 致命的

原因

  • SSE 是“永不结束的响应”

  • Gateway 会认为:

    “30 秒还没结束?那我关了”


✅ SSE 专用超时配置

spring:
  cloud:
    gateway:
      httpclient:
        connect-timeout: 5000
        response-timeout: 0s   # 关键

五、第三个坑:Header 被 Gateway “改坏了”

❌ 错误现象

  • 前端 EventSource 连不上

  • 或连接成功但不触发 onmessage

常见罪魁祸首

❌ Content-Type 被改写
Content-Type: application/json

而不是:

text/event-stream

✅ Gateway 必须“原样透传”

spring:
  cloud:
    gateway:
      default-filters:
        - PreserveHostHeader

并且不要在 Filter 里手动 set header。


六、第四个坑:HTTP/1.1 被无意中升级成 HTTP/2

问题表现

  • 某些客户端收不到流

  • 特别是 EventSource

原因

  • HTTP/2 对流量有额外 buffering

  • 某些浏览器 / 代理对 SSE + H2 支持不好


✅ 强制 Gateway 使用 HTTP/1.1

spring:
  cloud:
    gateway:
      httpclient:
        protocol: HTTP11

七、一个「能跑通 SSE 的 Gateway 路由示例」

spring:
  cloud:
    gateway:
      routes:
        - id: ai-sse
          uri: lb://mb-ai
          predicates:
            - Path=/ai/health_manager/stream
          filters:
            - StripPrefix=1

关键点总结:

  • 不改 response body

  • 不缓存

  • 不超时

  • 不动 header


八、前端为什么“必须立即有输出”?

很多人忽略了这一点。

SSE 的一个隐形规则

如果服务端迟迟不发送第一条 data,浏览器会以为连接失败

建议做法

AI 服务端:

emitter.send(" "); // 先发一个空事件

Gateway 才会立刻把连接“刷”给客户端。


九、排查 SSE 在 Gateway 卡死的 checklist

当你遇到“能连但不流”的情况,按顺序查:

  • Gateway response-timeout 是否为 0

  • 是否使用了 ModifyResponseBody

  • Content-Type 是否是 text/event-stream

  • 是否被 HTTP/2 代理

  • AI 是否第一时间发送 data

  • 是否被 nginx 二次代理缓冲


十、我的最终经验总结

SSE 在 Gateway 下不是“配置问题”,而是“思维问题”

你必须接受:

  • SSE 不是一个“普通 HTTP 响应”

  • Gateway 不应该“加工它”

  • 它只应该当一根“水管”

一旦你试图:

  • 解析

  • 缓存

  • 重写

👉 流式必死。


十一、什么时候我会“绕开 Gateway”?

说一句大实话:

  • 超高频 AI 流

  • 大并发长连接

  • 对延迟极敏感

👉 我会让前端直连 AI 服务

Gateway 只做:

  • 鉴权

  • 路由发现


十二、写在最后

如果你在做:

  • AI 对话

  • ChatGPT 类应用

  • 实时推送

那你迟早会和 SSE + Gateway 正面交锋。

希望这篇文章,能帮你少踩几个“线上才会爆”的坑。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐