问题出现得很突然,日志倒是留得挺全。前端用 new EventSource('/api/chat/stream') 订阅回答,网关要求 Authorization: Bearer,浏览器直接返回 401,控制台提示 EventSource 的 init 只支持 withCredentials,换成 fetch 请求同一个地址能通。

刚开始盯着「网关只认 Authorization,不认 cookie 会话」,折腾了半个多小时,排掉了。

真正麻烦的地方在于,几个原因的现象几乎一样。EventSource 规范不支持自定义请求头。少数情况下是cookie 的 SameSite 设置导致跨站不发送。

还有一种情况,预检请求被网关拒绝,浏览器放弃连接。

动手时先用 curl 带 Bearer 确认服务端本身正常

curl -N https://api.example.com/chat/stream -H "Authorization: Bearer $TOKEN"

前端改用 fetch 加 ReadableStream 手工解析 SSE

python -c "print('switch to fetch stream parser')"

服务端签发一次性短时 ticket 供 EventSource 使用

curl -s -X POST https://api.example.com/stream/ticket -H "Authorization: Bearer $TOKEN"

网关侧校验 ticket 并限制只能用一次

python verify_ticket.py --ttl 60 --single-use

怎么算真的好了,看的是同一批现象。EventSource 带 ticket 参数能建立连接并持续收到 data,ticket 过期后返回 401,正常请求不受影响。

容易忽略的是,把长期 token 放进 query 会留在访问日志里,用一次性 ticket 更稳妥,同时要把 ticket 的有效期压到几十秒并绑定用户。线上能稳定复现的问题都不算难,难的是只在大流量下才出现的那种。

作者 9823189