Fiber 框架不内置 HTTP 请求级超时控制,需开发者在中间件或 Handler 层显式实现;其 Read/WriteTimeout 属 TCP 连接层超时,非业务处理超时;推荐用 context.WithTimeout 实现单路由或全局超时中间件,并注意网关层超时对齐。

Fiber 框架本身 不内置 HTTP 请求级超时控制(比如类似 Spring Boot 的 spring.mvc.async.request-timeout),它的超时必须由开发者在中间件或 Handler 层显式实现。直接配个配置项就生效?不存在的。
为什么 Fiber 没有全局 request-timeout 配置
Fiber 是基于 Fasthttp 的轻量级 Go Web 框架,Fasthttp 本身不维护连接生命周期中的“业务处理超时”语义 —— 它只管读请求、写响应、复用连接。超时逻辑属于业务层责任,框架不会替你决定“这个接口该卡多久”。
所以你看到的 fiber.Config{WriteTimeout} 或 ReadTimeout 实际上是 TCP 连接层面的超时(对应 net/http 的 ReadTimeout/WriteTimeout),不是“Handler 执行超时”。
常见误解:设了 WriteTimeout: 5 * time.Second,结果 Handler 跑了 10 秒还没返回,却没触发超时 —— 因为它只限制「写响应头/体」耗时,不约束 c.Next() 之后的执行。
给单个路由加执行超时:用 context.WithTimeout
这是最常用、最可控的方式。在 Handler 内部创建带超时的 context.Context,并把该 context 传给下游调用(DB 查询、HTTP client、sleep 等):
app.Get("/slow", func(c *fiber.Ctx) error {
// 设置 Handler 自身执行上限为 3 秒
ctx, cancel := context.WithTimeout(c.Context(), 3*time.Second)
defer cancel()
<pre class="brush:php;toolbar:false;">select {
case <-time.After(5 * time.Second): // 模拟慢操作
return c.Status(fiber.StatusRequestTimeout).SendString("timeout")
case <-ctx.Done():
return c.Status(fiber.StatusRequestTimeout).SendString("handler timeout")
}})
关键点:
- 必须主动检查
ctx.Done()或把ctx传给支持 context 的函数(如db.QueryContext(ctx, ...)、http.Client.Do(req.WithContext(ctx))) - 单纯 defer cancel() 不会中断正在运行的 goroutine,得靠被调用方配合 context 取消
- 不要用
time.Sleep测试 —— 它不响应 cancel,应改用select { case
全局统一超时中间件:避免每个路由重复写
把超时逻辑抽成中间件,通过 fiber.New() 的 Config 或 Use() 注册:
func TimeoutMiddleware(timeout time.Duration) fiber.Handler {
return func(c *fiber.Ctx) error {
ctx, cancel := context.WithTimeout(c.Context(), timeout)
defer cancel()
<pre class="brush:php;toolbar:false;"> c.SetUserContext(ctx) // 把新 context 塞回 c
done := make(chan error, 1)
go func() {
done <- c.Next()
}()
select {
case err := <-done:
return err
case <-ctx.Done():
return c.Status(fiber.StatusRequestTimeout).SendString("request timeout")
}
}}
// 使用 app.Use(TimeoutMiddleware(2 * time.Second)) app.Get("/api/data", handler)
注意:
- 这里用 goroutine + channel 是为了非阻塞等待 Handler 结果;否则
c.Next()会同步执行,失去超时意义 - 中间件里的
c.Context()是原始 context,必须用c.SetUserContext()替换,确保下游能拿到带超时的新 context - 如果 Handler 内部又起了 goroutine 且没传这个 context,那些 goroutine 仍不会被取消
别漏掉:反向代理或网关层的超时也要对齐
Fiber 应用跑在 Nginx / Traefik / ALB 后面时,这些组件也有自己的超时设置,且默认往往比你的代码更短:
- Nginx:
proxy_read_timeout、proxy_connect_timeout - Traefik:
timeout在 routers 或 middlewares 中 - AWS ALB:
Idle timeout(默认 60s)
如果 Fiber Handler 设了 30s 超时,但 Nginx 的 proxy_read_timeout 是 10s,那用户永远收不到你的 StatusRequestTimeout,只会收到 Nginx 的 504。
所以最终生效的超时时间,是「所有链路中最短的那个」。排查超时问题时,第一反应不该是看 Fiber 代码,而是先查网关日志和配置。
真正容易被忽略的点就在这儿:Fiber 的超时必须手动编码实现,且要层层透传 context;而网关、负载均衡器、甚至客户端 SDK(比如前端 fetch 的 signal: AbortSignal.timeout())各自有一套超时逻辑,它们互不感知。一个请求卡住,你得挨个确认每一段的 timeout 值是否合理、是否生效、是否覆盖了全部路径。


















