应优先使用c.FullPath()获取注册路由路径,因其返回如"/api/v1/users/:id"的模板路径,适合路由维度统计;c.Request.URL.Path返回原始请求路径如"/api/v1/users/123",适合审计但难聚合,未匹配路由时FullPath为空需fallback。

直接用 c.Request.URL.Path 或 c.FullPath(),但二者语义不同,选错会导致日志路径不一致或为空
为什么 c.Request.URL.Path 有时记录的是原始路径而不是注册路由
HTTP 请求进来的原始路径(比如 /api/v1/users?id=123)会被 c.Request.URL.Path 原样返回,它不经过 Gin 的路由匹配解析。如果你注册的是 r.GET("/api/v1/users/:id", handler),而请求是 GET /api/v1/users/123,c.Request.URL.Path 仍是 /api/v1/users/123,不是带冒号的模板路径。
- 适合做「真实访问路径」审计,比如排查非法路径扫描
- 不适合做「路由维度统计」,因为相同路由可能有多个变体(如带/不带尾部斜杠、query 不同)
- 若需还原成注册时的路由模板,必须依赖 Gin 内部机制
c.FullPath() 才是你要的「注册路由路径」
c.FullPath() 是 Gin 在路由匹配完成后注入的字段,返回的是你代码里 r.GET("/xxx", ...) 中定义的原始 pattern,比如 /api/v1/users/:id。它在 c.Next() 前就已可用,且不受 query、fragment 影响。
- 必须在
c.Next()调用前读取,否则部分版本下可能为 ""(尤其在 panic 恢复中间件中) - 对未匹配路由(404)返回空字符串,建议加空值判断
- 示例:
path := c.FullPath(); if path == "" { path = c.Request.URL.Path }
生产环境建议:组合使用 + 标准化处理
只记 FullPath 容易漏掉未匹配路径;只记 Request.URL.Path 又导致聚合困难。折中做法是优先用 FullPath,fallback 到清洗后的原始路径。
立即学习“go语言免费学习笔记(深入)”;
- 去掉 query 和 fragment:
strings.SplitN(c.Request.URL.Path, "?", 2)[0] - 统一尾部斜杠(可选):
strings.TrimSuffix(path, "/") - 避免日志中出现敏感参数(如 token、auth code),可在清洗时正则过滤
- 不要在日志中间件里调用
c.GetHeader("X-Forwarded-For")等非必要操作——它不改变路径,但拖慢性能
最常被忽略的一点:Gin 的 Logger() 内置中间件默认用的就是 c.Request.URL.Path,不是 FullPath。如果你依赖它做监控归类,得自己重写或用 LoggerWithFormatter 替换格式函数。



















