Fiber 官方 Go Context 文档有个很容易让人误判的点:
fiber.Ctx 实现了 context.Context 接口。
所以你能这样写:
func doWork(ctx context.Context) error {
return nil
}
app.Get("/sync", func(c fiber.Ctx) error {
return doWork(c)
})这在“当前 handler 内”是可行的。
但官方也提醒了一个关键细节:
fiber.Ctx虽然实现了context.Context- 但它的
Deadline、Done、Err目前不是你期待中的完整取消语义
所以你不能天真地把它等同于“标准请求上下文的一切行为都可靠”。
#1. handler 外请用 c.Context()
如果你要把上下文带到 handler 外,比如异步任务、goroutine,请这样:
app.Get("/job", func(c fiber.Ctx) error {
ctx := c.Context()
go func(ctx context.Context) {
_ = doWork(ctx)
}(ctx)
return c.SendStatus(fiber.StatusAccepted)
})官方文档明确说了:
c.Context() 返回的 context.Context 才是可以在 handler 完成后继续安全使用的。
如果需要自定义:
app.Get("/job", func(c fiber.Ctx) error {
c.SetContext(context.WithValue(context.Background(), "requestID", "abc-123"))
ctx := c.Context()
go func(ctx context.Context) {
_ = doWork(ctx)
}(ctx)
return c.SendStatus(fiber.StatusAccepted)
})#2. 想做超时控制,自己包一层
app.Get("/slow", func(c fiber.Ctx) error {
ctx, cancel := context.WithTimeout(c.Context(), 2*time.Second)
defer cancel()
resultCh := make(chan string, 1)
go func() {
select {
case <-time.After(3 * time.Second):
select {
case <-ctx.Done():
return
case resultCh <- "done":
}
case <-ctx.Done():
return
}
}()
select {
case res := <-resultCh:
return c.SendString(res)
case <-ctx.Done():
return c.Status(fiber.StatusGatewayTimeout).SendString("timeout")
}
})这才是快线城区里比较靠谱的做法:
别假设请求结束后所有后台活会自动消失。你要自己设计取消和超时。