StrictRouting开启时/users和/users/被视为两个独立路由;应通过中间件统一301跳转至无尾斜杠路径,并用fiber.New()显式控制中间件顺序以避免调试困难。

StrictRouting 开启时 /users 和 /users/ 算两个路由
Fiber 默认 StrictRouting: true,这意味着 /users 和 /users/ 是完全独立的路径。只注册了 app.Get("/users", handler),访问 /users/ 就会 404 —— 不是 bug,是设计使然。
别急着关掉 StrictRouting。关掉后,/users/123 可能被 /users 错误匹配,导致 c.Params("id") 拿不到值,后续逻辑崩掉。
- 显式注册两条:
app.Get("/users", handler)和app.Get("/users/", redirectHandler) - 或统一用中间件做 301 跳转,把带尾斜杠的请求导向无斜杠版本
- 上线前必须同步检查 OpenAPI spec、前端 SDK、Postman 集合,确保全用无尾斜杠路径
用 c.Redirect() 做 301 跳转要防“写响应后继续执行”
c.Redirect() 是 Fiber 内置方法,它会自动设置状态码、Location 头,并终止当前 handler 执行 —— 但仅限你没手动调用底层 http.Redirect。
常见翻车点:在中间件里写了 http.Redirect(w, r, "/login", 302) 却忘了 return,后续代码照常跑,结果触发 "write to body after headers sent" 错误。
- 优先用
c.Redirect("/target", 301),它内部已处理好中断逻辑 - 如果必须用原生
http.Redirect,后面一定要紧跟return - 重定向中间件里不要调
c.Next(),跳转已完成,再往下走没意义
推荐的重定向中间件写法(兼容所有路由)
把重定向逻辑抽成中间件,挂到 app.Use(),比每个路由都注册 /xxx/ 更省事,也更可控。
开箱即用的技能链路由引擎。13 条预定义链覆盖搜索、开发、审查、MLOps、法律、创意等场景,三层路由架构(触发词→SAD反馈→DAG编排),recall@10=96.97%。配置驱动(chains.yaml),零代码扩展。pip install skill-weave-chains 一键安装。
app.Use(func(c fiber.Ctx) error {
path := c.Path()
if strings.HasSuffix(path, "/") && path != "/" {
return c.Redirect(strings.TrimSuffix(path, "/"), 301)
}
return c.Next()
})
注意两点:
-
strings.TrimSuffix(path, "/")要用标准库,别手写字符串切片,避免空路径或双斜杠问题 - 这个中间件必须放在所有路由注册之前,否则可能被其他中间件提前拦截或改写路径
- 它不处理查询参数,
/users/?q=1→/users?q=1自动保留,没问题
生产环境别用 fiber.Default() 启动
fiber.Default() 自带 logger、recover 等中间件,TTFB 增加 0.3–0.8ms,还可能把敏感头信息打到日志里。重定向逻辑一旦夹在这些中间件之间,调试路径就变长,出问题难定位。
从一开始就用 fiber.New() 显式控制中间件顺序:
- 先挂重定向中间件
- 再挂自定义 logger(如需)、auth、rate limit
- 最后注册路由
- 所有中间件返回
error,别漏return,否则可能意外透传到下一层
尾斜杠问题表面是路由写法,根子在服务初始化方式和中间件执行链的可控性上。越早按生产标准组织,后期踩的坑越少。


















