fiber默认不中断超时请求,因其基于fasthttp的共享goroutine模型且不自动注入可取消context;必须手动用context.withtimeout+显式监听ctx.done()实现超时控制,否则handler阻塞将拖垮服务。

直接中断请求连接不是 Fiber 的默认行为,它本身不主动 kill 长时间运行的 handler;必须靠 context.WithTimeout + 显式检查 ctx.Done() 实现主动退出,否则协程会一直卡住,拖垮连接池和内存。
为什么 Fiber 默认不中断超时请求
Fiber 基于 fasthttp,复用连接、无 Goroutine per request 模型,handler 运行在共享 goroutine 中;它不为每个请求自动注入超时 context,也不监控执行时长。一旦 handler 陷入阻塞(如未设 timeout 的 DB 查询、死循环、无响应的 HTTP 调用),该 goroutine 就被独占,后续请求排队等待 —— 表现为“服务假死”,但 app.Listen() 仍在跑、无 panic、无日志。
- fasthttp 不像 net/http 那样天然绑定 request.Context;Fiber 的
*fiber.Ctx是封装,其c.Context()返回的是底层 fasthttp 的 context,**不可用于 cancel 或 timeout 控制** - 你不能依赖
c.Context().Done()来判断超时,它只反映连接关闭,不反映业务超时 - 所有超时逻辑必须由你手动注入、传递、监听
正确注入超时 context 到 handler 内部
必须在 handler 启动时创建带超时的子 context,并把它传给所有可能阻塞的操作(DB、HTTP client、time.Sleep 等)。不要只包一层 goroutine 就以为安全了 —— 若没在关键路径上 select 监听 ctx.Done(),照样无效。
- 在 handler 开头调用
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second),别用c.Context() - 立刻
defer cancel(),防止 goroutine 泄露 - 把
ctx显式传给下游:比如db.QueryRowContext(ctx, ...)、httpc.Do(req.WithContext(ctx)) - 对纯计算或自定义阻塞操作,用
select手动监听:case
避免常见误用导致超时失效
很多写法看似加了 timeout,实际完全不起作用。最典型的是把超时 context 创建放在 goroutine 内部,或漏传、或用错对象。
-
错误:在 goroutine 里才建
context.WithTimeout→ 超时只杀 goroutine,主 handler 仍卡住 -
错误:调用
db.QueryRow(...)而非db.QueryRowContext(ctx, ...)→ DB 驱动根本不理会你的 ctx -
错误:用
time.AfterFunc触发c.SendString→ 发送发生在超时之后,但连接早已被复用或关闭,可能 panic 或静默失败 -
注意:Fiber 的
c.Next()和中间件链不感知超时;若超时发生在中间件中,需手动return终止流程,否则继续往下走
配合全局请求超时中间件统一管控
重复写 WithTimeout 很容易遗漏。推荐用中间件封装,但要注意:它只能控制 handler 执行时长,不能替代下游组件自身的 timeout 设置。
- 中间件内创建
ctx, cancel := context.WithTimeout(c.Context(), 8*time.Second)(这里可安全用c.Context(),因 fasthttp 的 context 支持 cancel) - 把
ctx存到c.Locals("req_ctx", ctx),供后续 handler 取用 - 在中间件结尾
select监听ctx.Done(),超时则return c.Status(408).Send() - 务必在 handler 中用
c.Locals("req_ctx")取出并传给 DB/HTTP 调用,而非重新创建
真正起效的超时,是每一层都参与的链式响应:中间件设限、handler 主动检查、DB 驱动识别 context、HTTP client 尊重 deadline。少任何一环,超时就变成摆设。最易忽略的是——你以为 DB 查询有超时,其实连 QueryRowContext 都没调用。











