全书目录

第三十三篇:Fiber 完全指南 —— 极简高压快线城区宇宙

第七章:`Ctx` —— 每辆车手里的临时通行牌

2 分钟 765 字 第 618 / 962 个阅读单元

这是 Fiber 最关键、也最容易翻车的部分。

官方 Welcome 和 Go Context 文档都在强调同一件事:

fiber.Ctx 以及从它拿到的很多值,只在当前 handler 生命周期内有效。处理完就会被复用。

这句话你必须咽下去。


#1. 为什么会这样

因为 Fiber 为了快,会尽量复用对象和底层缓冲区。

这就像快线城区为了吞吐量,不给每辆车都新造一套全新表单,而是:

  • 办完就回收
  • 下一辆车再复用

所以下面这种写法是危险的:

go
var saved string

app.Get("/users/:id", func(c fiber.Ctx) error {
    saved = c.Params("id") // 危险:底层值可能被后续请求复用
    return c.SendString(saved)
})

更危险的是把 c 本身扔进 goroutine:

go
app.Get("/job", func(c fiber.Ctx) error {
    go func() {
        _ = c.Params("id") // 危险:handler 返回后,c 可能已被复用
    }()
    return c.SendStatus(fiber.StatusAccepted)
})

#2. 正确姿势:只在当前 handler 内使用
go
app.Get("/users/:id", func(c fiber.Ctx) error {
    id := c.Params("id")
    return c.JSON(fiber.Map{"id": id})
})

如果你必须把值带出当前 handler,就复制:

go
app.Get("/users/:id", func(c fiber.Ctx) error {
    id := c.App().GetString(c.Params("id"))
    go func(userID string) {
        // 安全使用
        println(userID)
    }(id)

    return c.SendStatus(fiber.StatusAccepted)
})

如果你开启:

go
app := fiber.New(fiber.Config{
    Immutable: true,
})

则可以让上下文返回值变成可安全持久化的副本,但代价是性能会下降。

所以 Immutable 更像:

你把临时通行牌改成“一人一份正式复印件”,安全更高,速度略慢。


#3. Ctx 里到底装了什么

你可以把 fiber.Ctx 理解为“当前车辆的临时通行档案袋”,里面装着:

  • 路径参数:c.Params("id")
  • 查询参数:c.Query("page")
  • Header:c.Get("Authorization")
  • Cookie:c.Cookies("token")
  • 请求体读取与绑定:c.Bind()...
  • 响应状态:c.Status(...)
  • 返回 JSON / 字符串 / 文件:c.JSON(...)c.SendString(...)
  • 中间件链继续执行:c.Next()
  • 临时挂载值:c.Locals(...)

#4. Locals 是站内临时标签,不是数据库
go
app.Use(func(c fiber.Ctx) error {
    c.Locals("requestStart", time.Now())
    return c.Next()
})

app.Get("/x", func(c fiber.Ctx) error {
    start := c.Locals("requestStart").(time.Time)
    _ = start
    return c.SendStatus(fiber.StatusOK)
})

它适合放:

  • 当前请求的用户身份
  • 请求开始时间
  • 中间件传给下游的数据
  • request id
  • 访问控制结果

不适合放:

  • 跨请求共享状态
  • 全局缓存
  • 长生命周期对象