淺談Spring Cloud Gateway 轉(zhuǎn)發(fā) SSE 的那些坑
—— 為什么你本地能流,一上網(wǎng)關(guān)就“卡死”
一、背景:SSE 本地好好的,上了 Gateway 全廢了
在做 AI 問答流式輸出時(shí),我最初的架構(gòu)是這樣的:
Browser ↓ Spring Cloud Gateway ↓ AI Service(SSE)
現(xiàn)象非常詭異:
- 直連 AI 服務(wù):? 一邊生成一邊返回
- 走 Gateway:? 頁面一直 loading
- 最后一次性返回,或者直接超時(shí)
當(dāng)時(shí)的第一反應(yīng)是:
“是不是 SSE 不能過網(wǎng)關(guān)?”
結(jié)論是:
SSE 可以過 Gateway,但默認(rèn)配置下,幾乎一定會翻車
二、SSE 在 Gateway 場景下到底“特殊”在哪?
1?? SSE 的幾個(gè)關(guān)鍵特性
- 長連接
- 響應(yīng)體是持續(xù)寫入
- 沒有
Content-Length - 依賴
Transfer-Encoding: chunked
而 Gateway 的本質(zhì)是:
一個(gè)“智能代理” + 各種 Filter
這就產(chǎn)生了天然沖突。
三、第一個(gè)坑:響應(yīng)被 Gateway “緩存”了
? 錯誤表現(xiàn)
- AI 服務(wù)已經(jīng)在流式返回
- Gateway 一直等
- 最后一次性吐給客戶端
? 根本原因
Gateway 默認(rèn)會嘗試:
- 聚合 response body
- 處理后再返回
- 破壞了 SSE 的“邊寫邊發(fā)”
? 正確做法:禁止響應(yīng)緩存
spring:
cloud:
gateway:
httpclient:
response-timeout: 0s并且不要使用這些 Filter:
- ModifyResponseBody
- RewriteResponseBody
- CacheRequestBody
?? 這些 Filter 天生會吃掉流
四、第二個(gè)坑:超時(shí)設(shè)置會“悄悄殺死連接”
? 常見錯誤配置
spring:
cloud:
gateway:
httpclient:
connect-timeout: 5000
response-timeout: 30s對普通接口沒問題
對 SSE 來說是 致命的
原因
- SSE 是“永不結(jié)束的響應(yīng)”
- Gateway 會認(rèn)為:
“30 秒還沒結(jié)束?那我關(guān)了”
? SSE 專用超時(shí)配置
spring:
cloud:
gateway:
httpclient:
connect-timeout: 5000
response-timeout: 0s # 關(guān)鍵五、第三個(gè)坑:Header 被 Gateway “改壞了”
? 錯誤現(xiàn)象
- 前端 EventSource 連不上
- 或連接成功但不觸發(fā)
onmessage
常見罪魁禍?zhǔn)?/h3>
? Content-Type 被改寫
Content-Type: application/json
而不是:
text/event-stream
? Gateway 必須“原樣透傳”
spring:
cloud:
gateway:
default-filters:
- PreserveHostHeader并且不要在 Filter 里手動 set header。
六、第四個(gè)坑:HTTP/1.1 被無意中升級成 HTTP/2
問題表現(xiàn)
- 某些客戶端收不到流
- 特別是 EventSource
原因
- HTTP/2 對流量有額外 buffering
- 某些瀏覽器 / 代理對 SSE + H2 支持不好
? 強(qiáng)制 Gateway 使用 HTTP/1.1
spring:
cloud:
gateway:
httpclient:
protocol: HTTP11七、一個(gè)「能跑通 SSE 的 Gateway 路由示例」
spring:
cloud:
gateway:
routes:
- id: ai-sse
uri: lb://mb-ai
predicates:
- Path=/ai/health_manager/stream
filters:
- StripPrefix=1關(guān)鍵點(diǎn)總結(jié):
- 不改 response body
- 不緩存
- 不超時(shí)
- 不動 header
八、前端為什么“必須立即有輸出”?
很多人忽略了這一點(diǎn)。
SSE 的一個(gè)隱形規(guī)則
如果服務(wù)端遲遲不發(fā)送第一條 data,瀏覽器會以為連接失敗
建議做法
AI 服務(wù)端:
emitter.send(" "); // 先發(fā)一個(gè)空事件 Gateway 才會立刻把連接“刷”給客戶端。
九、排查 SSE 在 Gateway 卡死的 checklist
當(dāng)你遇到“能連但不流”的情況,按順序查:
- Gateway response-timeout 是否為 0
- 是否使用了 ModifyResponseBody
- Content-Type 是否是 text/event-stream
- 是否被 HTTP/2 代理
- AI 是否第一時(shí)間發(fā)送 data
- 是否被 nginx 二次代理緩沖
十、我的最終經(jīng)驗(yàn)總結(jié)
SSE 在 Gateway 下不是“配置問題”,而是“思維問題”
你必須接受:
- SSE 不是一個(gè)“普通 HTTP 響應(yīng)”
- Gateway 不應(yīng)該“加工它”
- 它只應(yīng)該當(dāng)一根“水管”
一旦你試圖:
- 解析
- 緩存
- 重寫
?? 流式必死。
十一、什么時(shí)候我會“繞開 Gateway”?
說一句大實(shí)話:
- 超高頻 AI 流
- 大并發(fā)長連接
- 對延遲極敏感
?? 我會讓前端直連 AI 服務(wù)
Gateway 只做:
- 鑒權(quán)
- 路由發(fā)現(xiàn)
十二、寫在最后
如果你在做:
- AI 對話
- ChatGPT 類應(yīng)用
- 實(shí)時(shí)推送
那你遲早會和 SSE + Gateway 正面交鋒。
到此這篇關(guān)于淺談Spring Cloud Gateway 轉(zhuǎn)發(fā) SSE 的那些坑的文章就介紹到這了,更多相關(guān)Spring Cloud Gateway 轉(zhuǎn)發(fā) SSE內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring security密碼加密實(shí)現(xiàn)代碼實(shí)例
這篇文章主要介紹了Spring security密碼加密實(shí)現(xiàn)代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04
SpringBoot如何使用RateLimiter通過AOP方式進(jìn)行限流
這篇文章主要介紹了SpringBoot如何使用RateLimiter通過AOP方式進(jìn)行限流,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-06-06
SpringMvc MultipartFile實(shí)現(xiàn)圖片文件上傳示例
本篇文章主要介紹了SpringMvc MultipartFile實(shí)現(xiàn)圖片文件上傳示例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-02-02
java動態(tài)代理(jdk與cglib)詳細(xì)解析
靜態(tài)代理:由程序員創(chuàng)建或特定工具自動生成源代碼,再對其編譯。在程序運(yùn)行前,代理類的.class文件就已經(jīng)存在了2013-09-09
Java實(shí)現(xiàn)通過IP獲取IP歸屬地的方法(離線+在線)
我們都知道安全攻擊都是在某臺客戶機(jī)上執(zhí)行某些惡意操作致使服務(wù)端響應(yīng)異常崩潰亦或響應(yīng)數(shù)據(jù)被篡改,首先我想到的是對訪問的web端做一個(gè)IP的校驗(yàn),那么我們首先得知道客戶端的IP是多少,接下來此文重點(diǎn)介紹如何獲得,需要的朋友可以參考下2023-10-10

