不能靠http.Server的ReadTimeout/WriteTimeout设置单个请求超时,因其仅作用于连接建立和响应写出;Gin需用context.WithTimeout配合业务层主动检查ctx.Err(),并注意WriteTimeout对pprof采集的影响。

不能靠 http.Server 的 ReadTimeout/WriteTimeout 设置单个请求超时 —— 它们只管连接建立和响应写出,对已进入 handler 的请求完全无效。
为什么 Gin 里必须用 context.WithTimeout
Gin 的 handler 是同步执行的,没有内置异步取消机制。超时信号只能通过 context.Context 传递,且业务逻辑必须主动检查 ctx.Err() 并响应。常见错误包括:
- 只调用
context.WithTimeout却没在 DB 查询、HTTP 调用等耗时操作中传入该ctx - 用
time.Sleep或纯计算模拟耗时,但没定期select监听ctx.Done() - 启动子 goroutine 后忘记把
ctx传进去,导致超时后 goroutine 仍在运行
怎么写一个可靠的超时中间件
封装成中间件最实用,但要注意它只负责设子 ctx 和兜底响应,不替代业务层的超时检查。示例:
func TimeoutMiddleware(timeout time.Duration) gin.HandlerFunc {
return func(c *gin.Context) {
ctx, cancel := context.WithTimeout(c.Request.Context(), timeout)
defer cancel()
c.Request = c.Request.WithContext(ctx)
<pre class="brush:php;toolbar:false;"> c.Next()
if ctx.Err() == context.DeadlineExceeded {
c.AbortWithStatusJSON(http.StatusGatewayTimeout, gin.H{"error": "request timeout"})
}
}}
开箱即用的技能链路由引擎。13 条预定义链覆盖搜索、开发、审查、MLOps、法律、创意等场景,三层路由架构(触发词→SAD反馈→DAG编排),recall@10=96.97%。配置驱动(chains.yaml),零代码扩展。pip install skill-weave-chains 一键安装。
使用方式:
router.GET("/api/data", TimeoutMiddleware(5*time.Second), dataHandler)-
c.AbortWithStatusJSON必须配合c.Abort()(AbortWithStatusJSON内部已含) - 若 handler 中启动了 goroutine,需显式传
ctx并监听取消
容易被忽略的坑:Gin 的 WriteTimeout 会影响 pprof CPU profile
当用 gin-contrib/pprof 采集 CPU profile(如 /debug/pprof/profile?seconds=30)时,如果 http.Server.WriteTimeout 小于采集时长,响应会被提前中断,导致 profile 文件损坏。务必确认:
-
server.WriteTimeout >= 30 * time.Second(或更保守设为 60s) - 或显式缩短采集时间,例如
?seconds=15,并匹配超时设置 - 这个限制和路由超时中间件无关,是 HTTP 服务器层的硬约束
真正难处理的是那些不响应 ctx.Done() 的操作,比如 Cgo 调用、某些底层系统调用,或者没设计上下文支持的老库 —— 这类场景下,超时中间件只能做到“不发响应”,无法强制终止执行。










