Fiber 框架不支持 per-route 超时,因其基于 Fasthttp 且遵循“轻量、显式”设计哲学;超时需通过中间件结合 ctx.Context() 与手动 abort 实现,全局仅支持 server 级 ReadTimeout/WriteTimeout。

Fiber 框架不支持直接在路由定义里写 timeout 参数(比如 app.Get("/api", handler).Timeout(5 * time.Second) 这种链式调用并不存在)——它压根没提供原生的 per-route 超时 API。
为什么 Fiber 没有 Route.Timeout() 方法
Fiber 基于 Fasthttp,而 Fasthttp 本身不内置请求级超时控制;它的连接生命周期由 server 级配置统一管理。Fiber 的设计哲学是“轻量、显式、不封装魔法”,所以超时必须由开发者自己注入中间件或在 handler 内部控制,而不是靠框架自动中断协程。
- 所有路由共享同一个
fiber.Config中的ReadTimeout/WriteTimeout,这是全局连接层超时,不是业务逻辑超时 - 你无法对
/health设 2 秒、对/report设 60 秒——除非拆成两个独立fiber.App实例(不现实) - 试图用
context.WithTimeout()包裹整个 handler 是常见误用:Fasthttp 的Ctx不是标准net/http的Request.Context(),它不传播 cancel 信号给底层连接
真正能生效的 per-route 超时方案:用中间件 + ctx.Timeout() + 手动 abort
核心思路:在中间件中启动带超时的 goroutine 处理业务逻辑,主 goroutine 监听超时并主动终止响应。注意——这不能 kill 已运行的 handler,只能防止它继续写 body,所以 handler 内部也得配合检查中断信号。
- 必须用
ctx.Context()(Fiber v2.40+ 支持),而非ctx.Locals或自定义字段传参 - 超时后调用
ctx.Status(408).SendString("Request timeout"),再立即 return,否则可能 panic 或写重复 header - 业务 handler 中需定期检查
ctx.Context().Done(),比如在长循环、DB 查询前后加select { case - 示例中间件:
func TimeoutMiddleware(timeout time.Duration) fiber.Handler {
return func(c *fiber.Ctx) error {
done := make(chan error, 1)
go func() {
done <- c.Next()
}()
<pre class="brush:php;toolbar:false;"> select {
case err := <-done:
return err
case <-time.After(timeout):
c.Status(fiber.StatusRequestTimeout).SendString("Request timeout")
return nil // 阻止后续中间件执行
}
}}
开箱即用的技能链路由引擎。13 条预定义链覆盖搜索、开发、审查、MLOps、法律、创意等场景,三层路由架构(触发词→SAD反馈→DAG编排),recall@10=96.97%。配置驱动(chains.yaml),零代码扩展。pip install skill-weave-chains 一键安装。
然后挂载到特定路由:app.Get("/slow-report", TimeoutMiddleware(30*time.Second), reportHandler)
容易被忽略的关键点:超时 ≠ 取消,handler 必须自行退出
上面的中间件只解决了“不等了、返回 408”,但 reportHandler 里的数据库查询或 HTTP 调用仍在后台跑。如果 handler 不检查 ctx.Context().Done() 并提前 return,就会造成 goroutine 泄漏 + 资源浪费。
- HTTP 客户端(如
resty或http.Client)必须显式传入ctx.Context(),否则超时中间件无效 - 数据库操作(如
pgx、gorm)也要用带 context 的方法,例如db.WithContext(ctx.Context()).Find(&users) - 纯 CPU 密集型计算无法被 context 中断,需手动插入检查点,否则超时中间件只是“假装超时”
真正起作用的 per-route 超时,永远是中间件 + handler 协同的结果,缺一不可。别指望框架替你杀掉正在跑的 goroutine。


















