应使用 c.OriginalURL() 提取原始路径:strings.SplitN(c.OriginalURL(), "?", 2)[0] 并经 url.PathUnescape() 解码和 filepath.Clean() 净化,避免误用 c.Path()(返回路由模板)或 c.Request().URI().Path()(可能被中间件篡改)。

中间件里拿不到 c.Path()?默认返回的是解析后路径
Fiber 的 c.Path() 在中间件中返回的是“去参数化后的路径”,比如请求 /user/123/profile,注册路由是 /user/:id/profile,那么 c.Path() 返回的就是 /user/:id/profile,不是原始 URL。这不是 bug,是设计使然——Fiber 路由匹配完成后,会把参数节点(:id)作为模板标识保留下来,供后续 handler 使用。但中间件若需做日志脱敏、路径白名单校验或反向代理重写,就得拿到真实请求路径。
用 c.OriginalURL() 提取原始路径部分
c.OriginalURL() 返回完整的原始请求 URL(含 query),需要手动切分出 path 段。它比 c.Request().URI().String() 更可靠,因为后者可能被中间件提前修改(如 fasthttp 底层复用 buffer)。
- 获取原始路径:
strings.SplitN(c.OriginalURL(), "?", 2)[0] - 注意 URL 编码未自动解码:若路径含
%20或%E4%BD%A0,需调url.PathUnescape()手动解码 - 不要直接拼接进文件系统:原始路径可能含
../,必须先做filepath.Clean()防目录穿越
为什么不能用 c.Request().URI().Path()
c.Request().URI().Path() 看似最直接,但它在 Fiber v3 中存在两个隐蔽问题:
- 某些中间件(如
compress、recover)会在执行前修改 URI buffer,导致多次调用返回不一致值 - 当路由启用
StrictRouting: true且请求路径末尾多了一个/(如注册/api却访问/api/),URI().Path()可能返回重定向后的规范化路径,而非客户端原始发送值 -
c.OriginalURL()是 Fiber 在请求进入第一层路由前就快照下来的,稳定性更高
真实场景:IP 白名单中间件需校验原始路径前缀
比如只允许 192.168.1.0/24 访问 /admin/* 下所有路径,但又不想让内网用户绕过鉴权直接请求 /api/internal/debug。这时中间件逻辑必须基于原始路径判断,而不是 c.Path() 返回的 /admin/:section 这类模板。
开箱即用的技能链路由引擎。13 条预定义链覆盖搜索、开发、审查、MLOps、法律、创意等场景,三层路由架构(触发词→SAD反馈→DAG编排),recall@10=96.97%。配置驱动(chains.yaml),零代码扩展。pip install skill-weave-chains 一键安装。
示例关键片段:
func ipWhitelist(c *fiber.Ctx) error {
ip := c.IP()
if !isInInternalSubnet(ip) {
return c.Status(fiber.StatusForbidden).SendString("IP not allowed")
}
origPath := strings.SplitN(c.OriginalURL(), "?", 2)[0]
if strings.HasPrefix(origPath, "/admin/") || origPath == "/admin" {
return c.Next()
}
return c.Status(fiber.StatusForbidden).SendString("Access denied")
}
这里如果误用 c.Path(),遇到 /admin/settings 会被转成 /admin/:section,strings.HasPrefix() 就失效了。
原始路径这事容易被忽略,尤其在做审计日志或安全策略时——你以为记录的是用户发来的路径,其实记的是路由模板。务必在中间件开头就提取并缓存 c.OriginalURL() 的 path 部分,别等后面 handler 改了上下文才想起来。










