fiber.recover()必须在fiber.new()后立即注册,且置于所有中间件之前,否则panic将直接崩溃进程;兜底404中间件需放在路由注册之后、app.use()链末尾;recover中不可调c.next(),结构体返回json须显式添加json tag。

fiber.Recover() 必须在 fiber.New() 后立即注册
不加 fiber.Recover(),panic 会直接 crash 进程,连日志都不留。它不是可选插件,是生产环境的强制依赖。
常见错误是把它塞在路由注册之后、或者和其他中间件混在一起调用。正确顺序只有一条:在 app := fiber.New() 之后,第一行 就注册它。
-
fiber.Recover()必须放在所有其他中间件(包括app.Use())之前,否则 panic 会在到达它之前就终止整个中间件链 - 别用
fiber.Default()替代fiber.New()—— 它自带的 logger 会在 panic 时狂打堆栈,线上容易冲垮日志系统 - 如果用了自定义
fiber.Config,确保没禁用DisableStartupMessage外还漏掉 recover 配置;recover 不是 config 项,必须显式调用
兜底 404 中间件要放在 app.Use() 最末尾
Fiber 不会自动返回 JSON 格式的 404,也不走 fiber.Recover()。未匹配路由默认是空响应体 + 404 状态码,前端很难识别。
你需要手动补一个兜底中间件,且必须确保它在所有 app.Get()/app.Post() 之后、app.Use() 链的最末端执行。
- 写法示例:
app.Use(func(c *fiber.Ctx) error { return c.Status(404).JSON(fiber.Map{"error": "not found"}) }) - 这个中间件不能放在
fiber.Recover()前面,否则 404 请求也会被 recover 拦住(recover 只管 panic,但位置错会导致逻辑混乱) - 别把它和权限校验、日志等中间件写成同一个
app.Use()函数——职责必须分离,否则 404 会误触发鉴权逻辑
recover 中不能再写响应体
一旦 c.Status(500).JSON(...) 或 c.SendString(...) 被调用,Fiber 内部标记该响应为 “committed”。此时再调 c.Next(),后续所有中间件都会被跳过。
典型翻车场景:你在 recover 中写了错误响应,又顺手加了 c.Next() 想继续走监控或日志中间件——实际完全无效。
- recover 中只做三件事:记录日志(含
debug.Stack())、设置状态码、写响应体;做完就结束,不要调c.Next() - 如果需要统一日志,把日志逻辑提前到 recover 中间件最开头,而不是靠
c.Next()传递 - 注意:HTTP header 已写入后调
c.JSON()会 panic,所以 recover 中务必先检查c.Response().Committed,但更稳妥的做法是——压根别在 recover 里依赖c.Next()
结构体返回 JSON 必须加 json tag
recover 中常会构造结构体返回错误信息,比如 fiber.Map{"code": 500, "msg": "internal error"} 是安全的,但自定义 struct 若没加 json: tag,字段会变成小写或直接丢弃。
Fiber 的 c.JSON() 底层走标准 json.Marshal(),不识别 Go 字段名,只认 tag。
- 错误写法:
type Resp struct { Code int; Msg string }→ 返回{} - 正确写法:
type Resp struct { Code int `json:"code"`; Msg string `json:"msg"` } - 别依赖 IDE 自动补全 tag——手敲,确认每个字段都有对应 tag,尤其嵌套结构体
- 如果用
fiber.Map,它本质是map[string]interface{},不用 tag,但 key 名必须是字符串,且不能含空格或特殊字符
recover 不是万能胶,它只拦当前 goroutine 的 panic。HTTP handler 里开的 go func() { ... panic() }(),主协程的 recover 完全看不见——这是线上排查超时 panic 时最容易忽略的盲区。











