记录一下那天晚上的排查过程。用 Go 1.22 写网关转发大模型的流式响应,客户端偶发 unexpected EOF,日志显示连接在 30 秒左右断开,服务端其实还在生成,用 curl -N 直连模型接口完全正常。
刚开始盯着「反向代理的读超时比生成时间短」,折腾了半个多小时,排掉了。
这类报错背后常见的原因有几处,逐个排除就行。http.Client 的 Timeout 覆盖整个请求 包括读流。少数情况下是Transport 的 ResponseHeaderTimeout 只等响应头。
另外,没设 IdleConnTimeout 连接被中间设备回收。
第一件事是确认是客户端超时还是上游断开
go run probe.go -url https://api.example.com/v1/chat/completions -timeout 0
然后把 Client.Timeout 置零 只保留响应头超时
go doc net/http.Client.Timeout
给流式请求单独建一个不设总超时的 Client
go run ./cmd/stream -model gpt-4o-mini
等前面都确认过,再抓包看 FIN 从哪一侧先发
tcpdump -i any -w sse.pcap port 443
别只看报错消失,验证要多做一步。长回答能完整读到结束标记,连接不再在 30 秒被切断,抓包里 FIN 由客户端在收完后发出。
这里还有个坑。Go 的 Timeout 是总时长,流式场景要设 0 再用 context 控制取消,不然回答越长越容易被自己的客户端掐断。线上能稳定复现的问题都不算难,难的是只在大流量下才出现的那种。
