502是nginx与上游服务(如kratos)通信失败所致,非kratos自身问题;需检查kratos绑定地址、超时配置(read/write/idletimeout)、中间件panic捕获、network类型及nginx proxy_*参数匹配性。

Kratos 本身不处理 Nginx 502,502 是反向代理层(如 Nginx、Ingress)与后端 HTTP 服务之间通信失败的产物;Kratos 只负责正常响应请求——只要它没崩溃、没超时、没 panic,502 就不是它的锅。
为什么 Kratos 服务明明健康却报 502
常见现象:Kratos 的 /health 接口 curl 正常返回 200,日志无错误,但浏览器或客户端访问业务路径时频繁 502。本质是 Nginx 等代理在连接、发送或读取 Kratos 实例时超时或收不到合法 HTTP 响应。
-
upstream timed out (110: Connection timed out) while connecting to upstream:Nginx 连不上 Kratos 的监听地址(端口未开、防火墙拦截、Pod IP 不可达) -
upstream prematurely closed connection while reading response header from upstream:Kratos 进程提前关闭连接(panic、中间件写 header 后又 panic、HTTP handler 未正确 return) -
recv() failed (104: Connection reset by peer):Kratos 主动 RST,常见于 HTTP/2 协商失败、TLS 配置错、或启用了http.Server.ReadTimeout但值过小
Kratos 启动时必须检查的三项配置
Kratos 默认用 http.Server 启动 HTTP 服务,所有超时和连接行为由 Go 标准库控制,但框架封装可能掩盖细节。
- 确认
http.Server.Addr绑定的是:9000这类具体端口,而非localhost:9000—— 后者会导致容器内其他网络命名空间无法访问 - 显式设置
http.Server.ReadTimeout和http.Server.WriteTimeout,建议 ≥60s;若依赖 Nginx 的proxy_read_timeout,Kratos 超时必须更长,否则会先断连 - 禁用
http.Server.IdleTimeout或设为足够大(如 90s),否则空闲连接会被 Kratos 主动关掉,而 Nginx 还在复用该连接,触发 502
Nginx proxy_* 超时参数与 Kratos 的匹配逻辑
Nginx 的超时不是独立生效的,它和 Kratos 的超时存在隐含依赖关系。例如:
-
proxy_connect_timeout 5s:必须小于 Kratos 的http.Server.ReadTimeout,否则 Nginx 还没连上就被自己放弃 -
proxy_read_timeout 60s:必须小于 Kratos 的http.Server.ReadTimeout,否则 Kratos 先 close 连接,Nginx 收到 RST 后记为 502 -
proxy_send_timeout 60s:对应 Kratos 写响应体的耗时,若接口含大文件流式响应,需同步调大 Kratos 的WriteTimeout
典型安全配对:proxy_read_timeout 55s + Kratos ReadTimeout = 60s;proxy_connect_timeout 3s + Kratos ReadTimeout > 3s(因为连接阶段也计入 ReadTimeout)。
Kratos 中间件引发的 502 隐形陷阱
某些中间件(尤其是自定义日志、鉴权、熔断)会在 panic 后未 recover,导致整个 HTTP handler 崩溃,连接中断。此时 Nginx 收不到任何响应头,直接报 502。
- 检查是否在
middleware.Recovery()外层又套了自定义 panic 捕获,造成 recover 失效 - 避免在中间件里调用
w.WriteHeader(500)后继续执行逻辑——Go HTTP 栈不保证后续 write 不 panic,一旦 panic,连接就断 - 若用了
transport/http.NewServer并传入自定义http.Server,确认没覆盖Handler字段导致路由未注册(此时所有请求 404,但 Nginx 可能因后端无响应转为 502)
最易忽略的一点:Kratos 的 server.HTTP 配置中 Network 字段若误设为 unix,而 Nginx 仍用 http://127.0.0.1:9000 去连,必然 502——因为根本连不到。











