gin 中间件无法排除路由,只能在中间件内通过 c.request.url.path 精确匹配路径并提前 c.next() 或 c.abort() 来跳过逻辑;该字段已解码标准化、不含查询参数,比 c.fullpath() 更可靠;推荐用路由组分离公开与受保护接口以避免中间件膨胀。

不能靠中间件“排除”路由,只能让中间件在特定路径下跳过逻辑——Gin 本身不提供中间件白名单/黑名单机制,所有注册的中间件都会执行,关键在于你是否在中间件内部做路径判断并提前 c.Next() 或 c.Abort()。
为什么 c.Request.URL.Path 是最可靠的选择
Gin 的 c.Request.URL.Path 返回的是已解码、标准化后的路径(如 /user/save 不会带重复斜杠或 URL 编码),且不包含查询参数,适合做精确字符串匹配。它比 c.FullPath() 更稳定,后者依赖路由定义中的 pattern(比如 /user/:id),而实际请求可能匹配多个 pattern。
-
c.Request.URL.Path是原始 HTTP 请求路径,不受 Gin 路由注册方式影响 - 若用
c.FullPath()判断,当路由是/user/:id且请求为/user/123时,c.FullPath()返回/user/:id,无法区分具体 ID;但c.Request.URL.Path返回/user/123,可直接比对 - 注意:路径末尾斜杠是否一致需显式处理,比如
/api/v1/user和/api/v1/user/是两个不同字符串
如何在 auth 中间件里跳过 /health 和 /metrics
常见需求是让健康检查和监控端点绕过鉴权。不要试图“卸载”中间件,而是让它在这些路径上不执行校验逻辑,直接放行:
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
func auth() gin.HandlerFunc {
return func(c *gin.Context) {
path := c.Request.URL.Path
// 明确列出需跳过的路径
if path == "/health" || path == "/metrics" || path == "/readyz" {
c.Next() // 不做任何鉴权,直接进下一环节
return
}
// 正常执行 token 解析、角色校验等
token := c.GetHeader("Authorization")
if token == "" {
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "missing token"})
return
}
// ... 验证逻辑
c.Next()
}
}
- 用
==做精确匹配,避免正则引入意外行为 - 不要用
strings.HasPrefix(path, "/health"),否则/healthz也会被误跳过 - 如果路径带版本前缀(如
/v1/health),必须写全,或统一提取 base path 后再判断
用路由组隔离比中间件内判断更清晰
当排除路径较多或语义明确(如全部公开接口),优先用 r.Group() 分离,而不是在通用中间件里堆 if 条件:
// 公共路由组:不挂 auth 中间件
public := r.Group("")
public.GET("/health", healthHandler)
public.GET("/metrics", metricsHandler)
public.POST("/login", loginHandler)
// 受保护路由组:显式挂 auth
protected := r.Group("").Use(auth())
protected.GET("/user", userHandler)
protected.PUT("/user/:id", updateUserHandler)
- 结构更清晰,后续加新公开接口只需往
public组里加,不用改中间件代码 - 避免中间件膨胀:一个
auth()函数里塞十几个if path == ...很难维护 - 注意:Group 的前缀是路径前缀,
r.Group("/api")下注册GET("/health")实际路径是/api/health,别漏掉前缀
真正容易被忽略的点是:路径匹配必须考虑路由注册顺序和前缀叠加。比如你在 r.Group("/admin") 里挂了 auth(),又在全局 r.Use() 挂了一次,那 /admin/health 会先进入全局中间件——此时若全局中间件没做排除,就会重复校验甚至报错。所以排除逻辑要么集中放在一个中间件里,要么彻底交给路由分组控制。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










