fiber默认strictrouting为true,/users与/users/被视为不同路由,故/app.get("/users")对/users/返回404;应通过重定向中间件将带尾斜杠路径301跳转至无斜杠版本,并确保其注册在所有路由之前。

为什么 app.Get("/users") 对 /users/ 返回 404
Fiber 默认开启 StrictRouting: true,它把 /users 和 /users/ 当作两条完全独立的路由。你只注册了 app.Get("/users", handler),那访问 /users/ 就必然 404——这不是 bug,是设计行为。
常见错误是直接关掉 StrictRouting:fiber.New(&fiber.Config{StrictRouting: false})。这会让 /users/ 匹配到 /users 路由,但也会引发更隐蔽的问题:比如同时注册了 /users 和 /users/:id,关掉后 /users/123 可能被前者捕获,c.Params("id") 拿不到值。
真正稳的做法不是绕开规则,而是用重定向把带尾斜杠的请求统一处理掉。
用中间件实现 /xxx/ → /xxx 301 重定向
写一个轻量中间件,在路由匹配前检查路径是否以 / 结尾且长度 > 1,是则 301 跳转到无斜杠版本:
app.Use(func(c *fiber.Ctx) error {
path := c.Path()
if len(path) > 1 && strings.HasSuffix(path, "/") {
return c.Redirect(strings.TrimSuffix(path, "/"), fiber.StatusMovedPermanently)
}
return c.Next()
})
注意三点:
开箱即用的技能链路由引擎。13 条预定义链覆盖搜索、开发、审查、MLOps、法律、创意等场景,三层路由架构(触发词→SAD反馈→DAG编排),recall@10=96.97%。配置驱动(chains.yaml),零代码扩展。pip install skill-weave-chains 一键安装。
- 必须放在所有
app.Get()等路由注册之前,否则不会生效 -
c.Redirect(...)内部会自动调用c.SendStatus()并终止后续 handler,不用手动return后续逻辑 - 用
fiber.StatusMovedPermanently(301)而非 302,利于 SEO 和客户端缓存
重定向时别漏掉 query string 和 method
上面的 c.Redirect() 默认只传路径,会丢掉原始请求的 query 参数(如 ?page=2)和 method(POST 重定向后变 GET)。如果你需要保留 query:
改用 c.Request().URI().String() 拆解并重建 URL:
app.Use(func(c *fiber.Ctx) error {
uri := c.Request().URI()
path := string(uri.Path())
if len(path) > 1 && strings.HasSuffix(path, "/") {
newURI := string(uri.FullURI())
newURI = strings.TrimSuffix(newURI, "/")
return c.Redirect(newURI, fiber.StatusMovedPermanently)
}
return c.Next()
})
但要注意:Fiber 的 c.Redirect() 总是发 301/302 响应,不支持原样透传 POST 请求。如果业务强依赖 POST + 尾斜杠(极少见),就得改用显式双注册:app.Post("/form", h) 和 app.Post("/form/", h),而不是重定向。
重定向中间件要放在 fiber.New() 之后、路由注册之前
顺序错了就白写。典型初始化结构是:
app := fiber.New(&fiber.Config{
// 不要设 StrictRouting: false
})
<p>// ✅ 中间件必须在这里注册
app.Use(redirectTrailingSlash)</p><p>// ✅ 所有路由注册放在这之后
app.Get("/users", handler)
app.Get("/posts/:id", handler)</p><p>// ❌ 放在这里就晚了,路由已注册,中间件不生效
</p>
另一个容易忽略的点:如果你用了 app.All("*", ...) 或通配符路由,它可能在重定向中间件前就匹配成功,导致重定向失效。确保通配符路由也放在重定向中间件之后,或干脆不用 * ,改用明确路径。










