路由分组:Group 与嵌套分组
本章解决什么问题:接口多了之后,/api/users、/api/orders 这类“同前缀 + 同中间件”的路由如果平铺注册,前缀要写很多遍,中间件也不好统一挂。路由分组把“前缀拼接”与“组级中间件”打包管理。
Group 的基本用法
r.Group(path) 返回一个 RouterGroup,组内再注册的路由自动带上组前缀:
package main
import (
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
api := r.Group("/api") // 组前缀 /api
{
api.GET("/users", func(c *gin.Context) {
c.JSON(200, gin.H{"ok": true})
})
api.POST("/users", func(c *gin.Context) {
c.JSON(201, gin.H{"created": true})
})
}
v1 := api.Group("/v1") // 嵌套:完整前缀 /api/v1
v1.GET("/ping", func(c *gin.Context) {
c.JSON(200, gin.H{"path": c.FullPath()})
})
r.Run(":8080")
}
代码里的大括号本身没有语法作用(Go 中就是普通块语句),只是用来缩进组内注册,让“这一块都属于 api 组”一目了然。c.FullPath() 返回命中路由的完整注册路径(含参数占位符原样),调试很有用。
组级中间件
Group 的第二大能力是“组级中间件”:注册到组里的路由执行前都会先跑组中间件,可以理解为“只对组内生效的 Use”。例如只对管理接口做鉴权:
admin := r.Group("/admin", authRequired()) // 第二参数起都是中间件
admin.GET("/stats", func(c *gin.Context) { c.JSON(200, gin.H{"ok": true}) })
其中 authRequired() 返回 gin.HandlerFunc(自定义中间件写法见第 13 章);等价写法是先 Group 再调用 group.Use(authRequired())。
嵌套分组的典型场景
版本化 API 常用嵌套分组:v1/v2 各自成树,方便灰度与新老版本并存。分组可以任意嵌套,内层前缀叠加在外层之上,中间件也按“外层先、内层后”的顺序叠加执行。
关键点
- Group 只做两件事:拼前缀、挂中间件,不引入新的请求语义。
- 组级中间件按“引擎级 → 外层组 → 内层组 → 路由级”的顺序叠加执行(下一章讲执行机制)。
- 分组不影响 NoRoute、NoMethod 等全局行为,它们仍挂在引擎上。
小结
分组把前缀管理与局部中间件合二为一,版本化 API 与管理后台这类布局基本都靠它。下一章深入中间件的执行顺序与 c.Next/c.Abort。