这个坑值得记一笔。自建流式问答接口放在 Nginx 后面,前端用 EventSource 消费,网络抖动后浏览器自动重连,页面上同一段回答出现两遍,服务端日志显示两次请求都从第一条开始推,事件里的 id 字段一直是空的。
刚开始盯着「服务端忽略请求头里的 Last-Event-ID,仍然从头生成」,折腾了半个多小时,排掉了。
把日志和配置对完,能解释这个现象的基本就这几处。服务端没有给每个事件写 id,浏览器没有值可以回传;重连时前端新建了 EventSource,没有复用上次的 lastEventId;网关默认把头过滤掉,上游根本收不到这个字段。
第一件事是在服务端给每个 chunk 写递增 id
print('id: %d\ndata: %s\n\n' % (seq, json.dumps(chunk)), flush=True)
手工带上该头请求一次看是否被处理
curl -N -H "Last-Event-ID: 42" http://127.0.0.1:8000/stream
服务端按该头跳过已发送的片段
python replay.py --from-seq 42 --stream
末了在网关侧确认这个头能透传到上游
curl -sI http://gw/stream -H "Last-Event-ID: 42" | grep -i event
怎么算真的好了,看的是同一批现象。断网十秒后恢复,页面只有一段回答,服务端日志里第二次请求的起始序号接着上次,计费也不重复。
EventSource 会自动重连也会自动带 Last-Event-ID,前提是服务端写了 id,缺这一行前端做什么都白搭。报错文案容易误导,真正的原因往往在相邻那一层的日志里。
