用context.WithTimeout包裹耗时操作是最直接的方式:以c.Context()为父context创建带超时的子context,按需在handler内对数据库、HTTP等I/O操作显式传入,避免复用c.Context()于goroutine,并务必defer cancel()防止泄漏。

用 ctx.Context() 包裹耗时操作是最直接的方式
Fiber 的 c.Context() 返回的是 Go 原生的 context.Context,它本身不带超时,但你可以用它作为父 context,再套一层 context.WithTimeout 或 context.WithDeadline。关键点是:别直接对 c 本身设超时,而是对你要执行的子任务设。
常见错误是把超时逻辑写在中间件里统一拦截——Fiber 没有内置“全局请求超时中间件”,强行加可能中断正常流(比如文件上传、长轮询)。正确做法是在具体 handler 内按需控制:
- 数据库查询、HTTP 调用、Redis 操作等 I/O 动作,必须显式传入带超时的
ctx - 避免在 goroutine 中直接用
c.Context():它会被复用,跨协程使用可能读到错误的上下文或 panic - 超时后记得调用
cancel(),否则 timer 会泄漏
ctx, cancel := context.WithTimeout(c.Context(), 2*time.Second)
defer cancel()
err := db.QueryRowContext(ctx, "SELECT 1").Scan(&val)
if err != nil {
if errors.Is(err, context.DeadlineExceeded) {
return c.Status(504).SendString("db timeout")
}
return c.Status(500).SendString("db error")
}
别依赖 fasthttp.Server.ReadTimeout 做业务级超时
fasthttp.Server 确实有 ReadTimeout 和 WriteTimeout 字段,但它们作用于 TCP 连接层面:前者控制从 socket 读完完整 request header + body 的最大耗时,后者控制 write response 到 socket 的最大耗时。它们无法干预 handler 内部逻辑执行时间。
这意味着:
- 如果 handler 卡在死循环或锁竞争中,
ReadTimeout不会触发 - 如果下游服务响应慢,但你 handler 已经发出了请求并等待结果,这个 timeout 也无能为力
- 设得太短(如 1s)会导致大 body 请求(如 multipart/form-data)直接被切断
真正该配的是反向代理场景下的后端连接超时,比如用 fasthttp.HostClient 时设置 ReadTimeout 和 WriteTimeout —— 那才是对下游 HTTP 服务的约束。
限流 + 超时要分层设计,不能只靠一个机制
超时和限流解决的是不同问题:超时防单个请求 hang 死,限流防突发流量打垮服务。但在 Fiber 中,二者容易混淆,尤其当你用 sentinel 做限流时。
典型陷阱是:在限流 entry 之后才创建超时 context,导致限流等待本身也被计入 handler 总耗时,进而引发误超时。正确顺序是:
- 先创建带超时的
ctx(比如 3s) - 再用这个
ctx去调sentinel.Entry(...),因为Entry内部可能涉及网络通信(如连接 sentinel-server) - 最后才是业务逻辑,仍复用同一个
ctx
另外注意:sentinel.Entry 失败返回的 err 不代表超时,可能是连接失败、配置错误等;而 ctx.Err() 才是你需要判断的超时信号。
WebSocket 连接里超时处理更特殊
Fiber 的 WebSocket 支持基于 github.com/gofiber/contrib/websocket,它的 *websocket.Conn 没有内置超时,但你可以用 conn.SetReadDeadline 和 conn.SetWriteDeadline 控制单次读/写操作时限。
重点不是“整个连接存活多久”,而是每次消息交互的容忍窗口。例如:
- 客户端 30 秒没发 ping,就断开:用
conn.SetReadDeadline(time.Now().Add(30 * time.Second))在每次ReadMessage前重置 - 服务端生成响应太慢,避免阻塞后续消息:把耗时逻辑放进带
context.WithTimeout的 goroutine,超时则跳过WriteMessage - 不要在
for循环外设一次 deadline——它不会自动刷新
最易忽略的一点:WebSocket 的超时判定必须结合心跳帧(ping/pong),纯 TCP 层 timeout 对应用层语义无效。Fiber 的 websocket.Conn 默认已处理 ping/pong,你只需确保客户端按时发 ping,服务端就能感知连接活性。











