Fiber 本身不提供请求级超时控制,必须依赖 http.Server 的 ReadTimeout/WriteTimeout 或中间件中使用 context.WithTimeout() 实现;其基于 fasthttp 的极简设计使 *fiber.Ctx 无状态且不内置超时逻辑,ctx.Timeout() 并不存在。

直接说结论:Fiber 本身不提供请求级超时控制,必须靠 http.Server 的 ReadTimeout、WriteTimeout 或中间件 + context.WithTimeout() 实现;别指望 ctx.Timeout() 或框架配置项能拦住慢 handler。
为什么 Fiber 没有内置请求超时?
Fiber 基于 fasthttp,而 fasthttp 的设计哲学是“零分配 + 极简”,它把连接生命周期管理完全交给底层 net.Listener 和 http.Server。Fiber 的 *fiber.Ctx 是复用的、无状态的上下文对象,不持有任何超时逻辑——它甚至没有 Timeout() 方法(常见误查)。
你看到的 ctx.Timeout() 不存在;搜到的所谓“Fiber 超时配置”基本是混淆了 http.Client 超时或误读文档。
- 所有对请求处理时间的限制,必须在 handler 执行前或执行中主动注入
context.Context - Fiber 的路由匹配和中间件链本身不检查耗时,一个死循环 handler 会一直卡住 goroutine
- 框架默认也不启动任何定时器去中断运行中的 handler
用 http.Server 级超时拦住长连接
这是最粗但最稳的方式,适用于所有 handler 统一兜底。它由 Go 标准库的 http.Server 实现,在连接层生效,不依赖 Fiber 代码。
注意:Fiber v2.x 的 app.Listen() 内部封装了 http.Server,你可以传入自定义 server 实例:
srv := &http.Server{
Addr: ":3000",
ReadTimeout: 5 * time.Second, // 从读取 request header 开始计时
WriteTimeout: 10 * time.Second, // 从写 response header 开始计时
Handler: app.Handler(),
}
log.Fatal(srv.ListenAndServe())
-
ReadTimeout包含:TCP 握手完成 → 读完全部 request body → 进入 handler 前的全部时间 -
WriteTimeout从调用ctx.Send()等方法开始计时,超时后连接直接关闭,response 可能被截断 - 这两个值设得太小(如
用中间件 + context.WithTimeout() 控制 handler 执行时长
这是更精准的做法,能真正限制 handler 函数体执行时间,适合需要分级超时(比如 /health 100ms、/report 30s)的场景。
关键点:必须在 handler 执行前把带超时的 context.Context 注入 *fiber.Ctx,并在 handler 内部显式检查 ctx.Context().Done()。
示例中间件:
func TimeoutMiddleware(timeout time.Duration) fiber.Handler {
return func(c *fiber.Ctx) error {
ctx, cancel := context.WithTimeout(c.Context(), timeout)
defer cancel()
c.SetUserContext(ctx)
<pre class="brush:php;toolbar:false;"> select {
case <p>}</p><p>// 使用
app.Use("/api/", TimeoutMiddleware(8<em>time.Second))
app.Get("/api/report", func(c </em>fiber.Ctx) error {
// 在 handler 中检查是否超时
select {
case </p>
- 别只依赖中间件里的
select—— 它只拦住进入 handler 前,handler 内部仍可能无限循环 - 每个耗时操作(DB 查询、HTTP 调用、大计算)都应接收并传递该
ctx,比如db.QueryContext(ctx, ...) - Fiber 的
c.Context()默认是context.Background(),必须用c.SetUserContext()替换才生效
别踩这些坑
很多人试了超时没效果,往往卡在这几个地方:
- 用了
fiber.Default()启动服务,但没意识到它的http.Server是用默认参数(ReadTimeout=0),等于没设超时 - 在 handler 里调
time.Sleep()或死循环,却没在循环内检查ctx.Done(),超时信号永远不被响应 - 以为
client.Timeout(下游 HTTP 调用)能控制当前请求超时——它只影响httpClient.Do(),跟 Fiber 请求生命周期无关 - 给
context.WithTimeout()传了time.Now().Add(...),而不是基于c.Context()派生,导致取消信号无法传播到子 goroutine
真正要命的是:超时不是“自动熔断”,而是你得在每一处阻塞点主动轮询或传入 ctx。没人替你做这件事,Fiber 更不会。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











