fiber上线前必须用fiber.new()替代fiber.default()并禁用默认logger等中间件,strictrouting需配合重定向处理斜杠,避免ctx.body()和strconv.atoi()性能陷阱,路由注册须在listen前完成且handler中禁止阻塞操作。

别信“框架快就万事大吉”——Fiber 默认配置在压测时大概率卡在 3 万 QPS 就开始抖,真正瓶颈从来不在路由树,而在你写的那几行 ctx.Body() 和没关掉的 fiber.Logger()。
为什么 fiber.Default() 上线等于自废武功
它自动挂了 Logger、Recover、RequestID 三个中间件,每秒几百次完整请求日志(含 Authorization 头)会直接打满磁盘 I/O。实测在 4 核 8G 环境下,首字节时间(TTFB)增加 0.3–0.8ms,高并发下延迟曲线立刻上翘。
- 开发阶段用
fiber.Default()没问题,省事 - 上线前必须切到
fiber.New(),再按需手动加中间件 - 真要日志,只记 error 级,或对接结构化日志系统(如 Loki + Promtail),别碰
fiber.Logger() - 检查是否误启用了其他带日志副作用的中间件,比如自定义 recover 包裹了
log.Printf
StrictRouting 导致 /users 和 /users/ 都 404 怎么办
这不是 bug,是默认行为:StrictRouting: true 把结尾斜杠视为路径差异。你只注册了 app.Get("/users", handler),那 GET /users/ 就必然 404。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- 别无脑设
StrictRouting: false——它会让/users和/users/:id冲突,/users/123可能被前者捕获,c.Params("id")拿不到值 - 推荐加统一重定向中间件:
app.Use()里判断路径以/结尾且不是根路径,用c.Redirect(strings.TrimSuffix(path, "/"), 301) - 上线前同步前端 SDK、OpenAPI 文档、反向代理规则,全部收敛到无尾斜杠格式
ctx.Body() 和 strconv.Atoi(ctx.Params("id")) 是性能黑洞
Fiber 底层复用 fasthttp 缓冲区,但 ctx.Body() 会触发完整内存拷贝,strconv.Atoi() 没缓存、不校验、panic 不可控,两者叠加能让 QPS 掉 30%+。
- 改用
ctx.BodyBytes()直接取底层[]byte引用(前提是你不修改内容) - 参数解析优先用
ctx.ParamsInt("id"),它内置缓存、跳过 panic、返回(int, error) - JSON 响应别先
json.Marshal()再Send(),直接c.JSON(200, data),Fiber 内部用了预分配 buffer - 静态文件服务别走中间件链,用
app.Static("/", "./public", fiber.Static{Next: func(c *fiber.Ctx) bool { return false }})
路由匹配没锁,但你的代码在阻塞
Fiber 的 Radix 树本身无锁,匹配是纯指针跳转,O(k) 时间完成。压测时延迟抖动,99% 是你在 handler 里干了不该干的事。
- 别在 handler 里同步调外部 HTTP 服务,必须套
c.Context().SetDeadline()(不是标准context.WithTimeout) - 数据库查询必须设
context.WithTimeout并配合理连接池大小(比如 16 核机器,MaxOpenConns=100起步) - 禁止在闭包里共享可变状态(如全局
map或slice),fatal error: concurrent map writes就是这么来的 - 所有路由注册必须在
app.Listen()之前完成,运行时不能动态app.Add()
最常被忽略的一点:Fiber 的 ctx.Locals 不会透传到原生 context.Context,对接 database/sql 或 redis-go 时,必须显式调 c.Context() 拿原生 context,否则超时、取消信号全失效。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










