自定义中间件必须实现 func(*fiber.Ctx) error 签名,显式调用 c.Next() 控制流程,返回非 nil error 会中断链;app.Use() 调用顺序决定执行顺序,路由级中间件在全局之后、handler 之前运行。

自定义中间件必须实现 func(*fiber.Ctx) error 签名,且不能依赖“自动执行 next”——是否调用 c.Next() 决定流程是否继续。
中间件函数签名和返回值怎么写才合法
Fiber 不定义独立的中间件类型,所有中间件本质就是 Handler:接收 *fiber.Ctx,返回 error。它和路由 handler 完全兼容,但语义上用于“横切逻辑”。
- 必须显式接收
*fiber.Ctx指针,不能传值或忽略 - 返回
error是强制的;返回非 nil 值会中断链(Fiber 将其视为错误并终止后续 handler) - 不调用
c.Next()就不会进入下一个中间件或路由 handler —— 这不是 bug,是控制权移交机制 - 常见错误:写了
c.Status(401).Send("no")却还调c.Next(),导致响应被覆盖或 panic
app.Use() 和路由内中间件执行顺序怎么控制
中间件执行顺序完全由 app.Use() 的调用顺序决定,没有优先级字段,也没有自动排序。你写的顺序 = 运行时入栈顺序。
- 全局中间件(
app.Use(mw1, mw2))一定在所有路由 handler 之前执行 - 路由级中间件(
app.Get("/x", mwA, handler))只对当前路由生效,且在全局中间件之后、handler 之前运行 - 多个
app.Use()调用按代码先后叠加:先app.Use(logMW),再app.Use(authMW),则 logMW 先拿到请求,authMW 后拿到 - 容易踩的坑:把日志中间件写在 auth 后面,结果认证失败直接 abort,日志根本没打出来
自定义中间件里怎么安全读取请求数据
Fiber 的 *fiber.Ctx 是复用对象,请求体(body)、查询参数(query)、路径参数(params)等都需按需提取,不能假设已解析或缓存。
- JSON body 必须显式调
c.BodyParser(&v),且v必须是指针;传值或漏&会导致静默失败(v保持零值) -
c.Query("key")只读 URL 查询字符串(?key=val),和c.Params("id")(来自/user/:id)完全无关 - 不要在中间件里反复调
c.Body()—— body 是 io.ReadCloser,只能读一次;如需多次使用,应提前bytes.NewReader(c.Body())或缓存到 ctx.Locals - 若中间件需要修改请求(如添加 header、重写 path),应在
c.Next()前完成;之后再改已无意义
为什么中间件里 return 了却还进了下一个 handler
根本原因:你调了 c.Next(),但没 return 当前函数。Fiber 不会自动跳出,它只看你的函数是否返回 error。
- 正确写法:
if !valid { return c.Status(400).SendString("bad") }—— 显式 return,终止链 - 错误写法:
if !valid { c.Status(400).SendString("bad"); c.Next() }—— Send 后仍继续执行,Next() 触发后续 handler,可能 panic 或覆盖响应 - 另一个常见问题:中间件中调用了
c.Redirect()或c.JSON()后忘记 return,结果下个 handler 又写了一次响应体 - 调试建议:每个中间件开头加
log.Printf("[mw] %s →", "name"),结尾加log.Printf("[mw] %s ←", "name"),一眼看出哪一层没退出
最易被忽略的一点:中间件里对 c.Locals 的写入是跨中间件共享的,但 c.Context()(底层 fasthttp.RequestCtx)在请求结束后会被重置 —— 所以别存指针或 goroutine 引用,只存简单值或短期生命周期对象。


















