路由分组本质是创建带前缀的子路由器,自动合并路径;中间件需显式挂载且按序执行,权限控制必须依赖中间件而非路径前缀,漏掉c.Abort()或错用.Use()将导致防护失效。

用 r.Group() 创建路由组,不是拼字符串
路由分组的本质是创建一个带前缀的子路由器,不是靠手动拼接路径字符串。比如写 r.Group("/api/v1"),再注册 .GET("/users"),最终生效的是 /api/v1/users —— 框架自动合并,你不用写 /api/v1/users 两次。
- 错误写法:
v1 := r.Group("/api/v1"); v1.GET("/api/v1/users", handler)→ 实际变成/api/v1/api/v1/users - 正确写法:
v1 := r.Group("/api/v1"); v1.GET("/users", handler) - 嵌套分组也一样:
admin := v1.Group("/admin"); admin.GET("/logs")对应/api/v1/admin/logs - 前缀必须以
/开头,但不能以//或多余斜杠结尾,否则可能匹配异常
中间件必须显式挂载到分组,Group 本身不带任何逻辑
Group 只负责路径前缀和路由隔离,不继承、不默认启用任何中间件。日志、JWT 鉴权、CORS 等都得自己调用 .Use() 显式绑定。
- 常见错误:以为
r.Use(JWTAuth())后所有分组自动受保护 → 实际上只影响全局注册后新增的路由,分组内仍需单独admin.Use(JWTAuth()) - 权限中间件要早于业务 handler 执行,且必须调用
c.Next()或c.Abort()控制流程 - 多个中间件按注册顺序执行(洋葱模型),
admin.Use(A(), B())表示请求先进 A,再进 B,再进 handler;响应则倒序 - 别在中间件里漏掉
c.Abort(),否则即使校验失败,handler 仍会执行(比如删库操作照常发生)
分组不隔离变量作用域,但中间件作用域是独立的
你在某个分组里定义的变量(比如 var usersHandler = func(...))对其他分组可见,但该分组调用的 .Use() 中间件不会影响其他分组或根路由。
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
- 全局中间件(
r.Use())和分组中间件(v1.Use())叠加生效,不是覆盖关系 - 如果全局注册了日志中间件,又在
/admin分组加了鉴权中间件,请求进来顺序是:日志 → 鉴权 → handler - 这意味着未授权请求也会被记日志——如果你不想暴露敏感行为,得把日志中间件移到鉴权之后,或在鉴权中间件里控制是否记录
- 分组之间完全独立,
v1.Group("/user")和v2.Group("/order")的中间件、路由、参数绑定互不影响
别用路径前缀代替权限控制
仅靠 r.Group("/admin") 并不能防止普通用户访问 /admin/users,它只是组织路由的手段。真正的权限必须靠中间件提取 token、解析 role 字段、做细粒度判断。
立即学习“go语言免费学习笔记(深入)”;
- 典型错误:给
/admin分组挂了 JWT 中间件,但没检查角色,导致普通用户也能进 - 推荐做法:写一个可配置角色的中间件,如
RoleRequired("admin"),并在分组上使用admin.Use(JWTAuth(), RoleRequired("admin")) - token 解析建议用
github.com/golang-jwt/jwt/v5,从claims["role"]或自定义字段取值,避免硬编码或类型断言失败 panic - 注意:中间件里用
c.Get("role")前,确保 JWT 中间件已成功 set 过该 key,否则会返回 nil
c.Abort() 或错一次 .Use() 调用位置,就可能让防护形同虚设。


















