必须用中间件+显式return实现重定向:因strictrouting=true时/users与/users/被视为不同路径,未注册后者则直接404;中间件需置于所有路由前,用c.redirect(newuri, fiber.statusmovedpermanently)显式返回,并校验len(path)>1防止根路径异常。

必须用中间件 + 显式 return 实现,不能依赖 StrictRouting 关闭或隐式跳转逻辑。
为什么 app.Get("/users") 对 /users/ 返回 404
Fiber 默认 StrictRouting: true,它把 /users 和 /users/ 当作两个完全独立的路径节点。你只注册了前者,后者根本不会进入任何 handler——连中间件都进不去,直接 404。这不是 bug,是 radix tree 路由匹配的必然结果。
- 别关
StrictRouting: false:会导致/users/:id和/users/123匹配冲突,c.Params("id")拿不到值 - 别只注册
app.Get("/users/", handler):治标不治本,所有带尾斜杠的路径都要重复写一遍 - 别指望
c.Next()在重定向后自动跳过后续逻辑:Fiber 不会帮你 abort,漏return就会触发write to body after headers sent
重定向中间件必须放在所有路由注册之前
中间件顺序决定执行时机。如果把它写在 app.Get() 后面,/users/ 请求压根不会经过它——因为 StrictRouting 已判定无匹配路由,直接返回 404。
开箱即用的技能链路由引擎。13 条预定义链覆盖搜索、开发、审查、MLOps、法律、创意等场景,三层路由架构(触发词→SAD反馈→DAG编排),recall@10=96.97%。配置驱动(chains.yaml),零代码扩展。pip install skill-weave-chains 一键安装。
- 正确位置:
app.Use(redirectMiddleware)必须在第一个app.Get()之前 - 必须显式
return c.Redirect(...),不能只调用c.Redirect()然后继续往下走 - 用
fiber.StatusMovedPermanently(301),不是 302;SEO 和客户端缓存更友好
如何保留 query string 和 method
c.Redirect() 默认只传路径,原始请求的 ?page=2 或 POST 方法都会丢失。需要手动重建完整 URI。
app.Use(func(c *fiber.Ctx) error {
uri := c.Request().URI()
path := string(uri.Path())
if len(path) > 1 && strings.HasSuffix(path, "/") {
// 保留 query 和 fragment
newURI := strings.TrimSuffix(string(uri.FullURI()), "/")
return c.Redirect(newURI, fiber.StatusMovedPermanently)
}
return c.Next()
})
-
uri.FullURI()包含 scheme、host、path、query、fragment,是最安全的源数据 - 不要用
c.Path() + "?" + c.QueryArgs().String():会漏掉 fragment,且未做 URL 编码校验 - 307 重定向可保留 method 和 body,但仅适用于内部跳转;对外部规范路径,仍推荐 301
重定向中间件和 404 中间件的顺序很关键
如果你还加了兜底 404 中间件(必须加),它得放在重定向中间件之后、所有路由注册之后。否则重定向还没触发,404 就已经发出去了。
- 正确顺序:
app.Use(redirectMiddleware)→app.Get(...)→app.Use(notFoundMiddleware) - 重定向中间件里判断的是
c.Path(),不是c.OriginalURL():后者可能被反向代理改写 - 测试时用
curl -I http://localhost:3000/users/看Location响应头是否正确,别只看页面跳转
最易忽略的点:重定向中间件里对根路径 "/" 的保护。如果没加 len(path) > 1 判断,strings.TrimSuffix("/", "/") 会得到空字符串,导致跳转到 // 这种非法路径。这个边界条件在线上流量突增时才会暴露。










