路由分组 #
一、路由分组概述 #
1.1 什么是路由分组 #
路由分组是将相关路由组织在一起的方式,可以统一添加前缀和中间件:
text
/api/v1/users
/api/v1/posts
/api/v1/comments
↓ 使用路由分组 ↓
group := r.Group("/api/v1")
{
group.GET("/users", ...)
group.GET("/posts", ...)
group.GET("/comments", ...)
}
1.2 分组优势 #
| 优势 | 说明 |
|---|---|
| 路径前缀 | 统一添加URL前缀 |
| 中间件共享 | 分组级别中间件 |
| 代码组织 | 模块化管理路由 |
| 版本控制 | 便于API版本管理 |
二、基本路由分组 #
2.1 创建路由分组 #
go
func main() {
r := gin.Default()
// 创建路由分组
api := r.Group("/api")
{
api.GET("/users", func(c *gin.Context) {
c.JSON(200, gin.H{"message": "get users"})
})
api.POST("/users", func(c *gin.Context) {
c.JSON(200, gin.H{"message": "create user"})
})
}
r.Run()
}
2.2 多级分组 #
go
func main() {
r := gin.Default()
// 多级分组
v1 := r.Group("/api/v1")
{
users := v1.Group("/users")
{
users.GET("", listUsers)
users.GET("/:id", getUser)
users.POST("", createUser)
users.PUT("/:id", updateUser)
users.DELETE("/:id", deleteUser)
}
posts := v1.Group("/posts")
{
posts.GET("", listPosts)
posts.GET("/:id", getPost)
}
}
r.Run()
}
2.3 分组嵌套 #
go
func main() {
r := gin.Default()
api := r.Group("/api")
{
v1 := api.Group("/v1")
{
users := v1.Group("/users")
{
users.GET("", listUsers)
// 深层嵌套
posts := users.Group("/:userId/posts")
{
posts.GET("", listUserPosts)
posts.GET("/:postId", getUserPost)
}
}
}
v2 := api.Group("/v2")
{
users := v2.Group("/users")
{
users.GET("", listUsersV2)
}
}
}
r.Run()
}
三、分组中间件 #
3.1 分组级别中间件 #
go
func main() {
r := gin.Default()
// 创建带中间件的分组
api := r.Group("/api")
api.Use(AuthMiddleware())
{
api.GET("/profile", func(c *gin.Context) {
c.JSON(200, gin.H{"message": "profile"})
})
api.GET("/settings", func(c *gin.Context) {
c.JSON(200, gin.H{"message": "settings"})
})
}
// 不需要认证的分组
public := r.Group("/public")
{
public.GET("/info", func(c *gin.Context) {
c.JSON(200, gin.H{"message": "public info"})
})
}
r.Run()
}
func AuthMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
token := c.GetHeader("Authorization")
if token == "" {
c.AbortWithStatusJSON(401, gin.H{"error": "unauthorized"})
return
}
c.Next()
}
}
3.2 多个中间件 #
go
func main() {
r := gin.Default()
api := r.Group("/api")
api.Use(
LoggerMiddleware(),
AuthMiddleware(),
RateLimitMiddleware(),
)
{
api.GET("/users", listUsers)
}
r.Run()
}
3.3 路由级别中间件 #
go
func main() {
r := gin.Default()
api := r.Group("/api")
{
// 单个路由添加中间件
api.GET("/users", AuthMiddleware(), listUsers)
// 多个中间件
api.GET("/admin",
AuthMiddleware(),
AdminMiddleware(),
adminHandler,
)
}
r.Run()
}
四、API版本控制 #
4.1 URL路径版本 #
go
func main() {
r := gin.Default()
// v1版本API
v1 := r.Group("/api/v1")
{
v1.GET("/users", getUsersV1)
v1.GET("/posts", getPostsV1)
}
// v2版本API
v2 := r.Group("/api/v2")
{
v2.GET("/users", getUsersV2)
v2.GET("/posts", getPostsV2)
}
r.Run()
}
4.2 请求头版本 #
go
func main() {
r := gin.Default()
r.GET("/api/users", func(c *gin.Context) {
version := c.GetHeader("API-Version")
switch version {
case "v2":
getUsersV2(c)
default:
getUsersV1(c)
}
})
r.Run()
}
4.3 版本中间件 #
go
func VersionMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
version := c.GetHeader("API-Version")
if version == "" {
version = "v1"
}
c.Set("version", version)
c.Next()
}
}
func main() {
r := gin.Default()
api := r.Group("/api")
api.Use(VersionMiddleware())
{
api.GET("/users", func(c *gin.Context) {
version := c.GetString("version")
switch version {
case "v2":
getUsersV2(c)
default:
getUsersV1(c)
}
})
}
r.Run()
}
五、RESTful API设计 #
5.1 RESTful规范 #
text
资源命名:
- 使用名词复数:/users, /posts
- 避免动词:/getUsers ❌ /users ✓
HTTP方法:
- GET 获取资源
- POST 创建资源
- PUT 更新资源(完整)
- PATCH 更新资源(部分)
- DELETE 删除资源
状态码:
- 200 成功
- 201 创建成功
- 204 删除成功(无内容)
- 400 请求错误
- 401 未授权
- 403 禁止访问
- 404 资源不存在
- 500 服务器错误
5.2 RESTful路由示例 #
go
func main() {
r := gin.Default()
// 用户资源
users := r.Group("/users")
{
users.GET("", listUsers) // 获取用户列表
users.POST("", createUser) // 创建用户
users.GET("/:id", getUser) // 获取单个用户
users.PUT("/:id", updateUser) // 更新用户(完整)
users.PATCH("/:id", patchUser) // 更新用户(部分)
users.DELETE("/:id", deleteUser) // 删除用户
// 用户相关资源
users.GET("/:id/posts", getUserPosts) // 用户的文章
users.GET("/:id/comments", getUserComments) // 用户的评论
}
// 文章资源
posts := r.Group("/posts")
{
posts.GET("", listPosts)
posts.POST("", createPost)
posts.GET("/:id", getPost)
posts.PUT("/:id", updatePost)
posts.DELETE("/:id", deletePost)
// 文章评论
posts.GET("/:id/comments", getPostComments)
posts.POST("/:id/comments", createComment)
}
r.Run()
}
5.3 响应格式规范 #
go
// 统一响应结构
type Response struct {
Code int `json:"code"`
Message string `json:"message"`
Data interface{} `json:"data,omitempty"`
}
type PageResponse struct {
Code int `json:"code"`
Message string `json:"message"`
Data interface{} `json:"data"`
Meta PageMeta `json:"meta"`
}
type PageMeta struct {
Page int `json:"page"`
Size int `json:"size"`
Total int64 `json:"total"`
TotalPage int `json:"totalPage"`
}
// 成功响应
func Success(c *gin.Context, data interface{}) {
c.JSON(200, Response{
Code: 0,
Message: "success",
Data: data,
})
}
// 创建成功
func Created(c *gin.Context, data interface{}) {
c.JSON(201, Response{
Code: 0,
Message: "created",
Data: data,
})
}
// 删除成功(无内容)
func NoContent(c *gin.Context) {
c.Status(204)
}
// 分页响应
func PageData(c *gin.Context, data interface{}, page, size int, total int64) {
c.JSON(200, PageResponse{
Code: 0,
Message: "success",
Data: data,
Meta: PageMeta{
Page: page,
Size: size,
Total: total,
TotalPage: int(math.Ceil(float64(total) / float64(size))),
},
})
}
六、路由组织最佳实践 #
6.1 模块化路由 #
routes/routes.go:
go
package routes
import (
"github.com/gin-gonic/gin"
)
func Setup(r *gin.Engine) {
SetupAPIRoutes(r)
SetupWebRoutes(r)
SetupAdminRoutes(r)
}
func SetupAPIRoutes(r *gin.Engine) {
api := r.Group("/api")
{
SetupUserRoutes(api)
SetupPostRoutes(api)
SetupCommentRoutes(api)
}
}
func SetupUserRoutes(r *gin.RouterGroup) {
users := r.Group("/users")
{
users.GET("", userHandler.List)
users.POST("", userHandler.Create)
users.GET("/:id", userHandler.Get)
users.PUT("/:id", userHandler.Update)
users.DELETE("/:id", userHandler.Delete)
}
}
func SetupPostRoutes(r *gin.RouterGroup) {
posts := r.Group("/posts")
{
posts.GET("", postHandler.List)
posts.POST("", postHandler.Create)
posts.GET("/:id", postHandler.Get)
posts.PUT("/:id", postHandler.Update)
posts.DELETE("/:id", postHandler.Delete)
}
}
func SetupCommentRoutes(r *gin.RouterGroup) {
comments := r.Group("/comments")
{
comments.GET("", commentHandler.List)
comments.POST("", commentHandler.Create)
}
}
main.go:
go
package main
import (
"myapp/routes"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
// 注册所有路由
routes.Setup(r)
r.Run()
}
6.2 路由注册器模式 #
go
package router
import (
"github.com/gin-gonic/gin"
)
type Router interface {
Register(r *gin.RouterGroup)
}
type RouterGroup struct {
routers []Router
}
func NewRouterGroup() *RouterGroup {
return &RouterGroup{}
}
func (g *RouterGroup) Add(r Router) {
g.routers = append(g.routers, r)
}
func (g *RouterGroup) Register(r *gin.RouterGroup) {
for _, router := range g.routers {
router.Register(r)
}
}
// 用户路由
type UserRouter struct {
handler *handler.UserHandler
}
func NewUserRouter(handler *handler.UserHandler) *UserRouter {
return &UserRouter{handler: handler}
}
func (r *UserRouter) Register(rg *gin.RouterGroup) {
users := rg.Group("/users")
{
users.GET("", r.handler.List)
users.POST("", r.handler.Create)
users.GET("/:id", r.handler.Get)
users.PUT("/:id", r.handler.Update)
users.DELETE("/:id", r.handler.Delete)
}
}
// main.go
func main() {
r := gin.Default()
// 初始化路由组
apiGroup := router.NewRouterGroup()
apiGroup.Add(router.NewUserRouter(userHandler))
apiGroup.Add(router.NewPostRouter(postHandler))
// 注册路由
api := r.Group("/api/v1")
apiGroup.Register(api)
r.Run()
}
七、路由分组技巧 #
7.1 条件分组 #
go
func main() {
r := gin.Default()
// 根据配置创建分组
if config.EnableAPI {
api := r.Group("/api")
setupAPIRoutes(api)
}
if config.EnableAdmin {
admin := r.Group("/admin")
admin.Use(AdminAuth())
setupAdminRoutes(admin)
}
r.Run()
}
7.2 动态分组 #
go
func main() {
r := gin.Default()
// 根据模块动态创建分组
modules := []struct {
name string
setup func(*gin.RouterGroup)
}{
{"users", setupUserRoutes},
{"posts", setupPostRoutes},
{"comments", setupCommentRoutes},
}
api := r.Group("/api")
for _, m := range modules {
group := api.Group(m.name)
m.setup(group)
}
r.Run()
}
八、总结 #
8.1 核心要点 #
| 要点 | 说明 |
|---|---|
| 创建分组 | r.Group(“/prefix”) |
| 分组嵌套 | 支持多级嵌套 |
| 分组中间件 | api.Use(middleware) |
| 版本控制 | URL路径或请求头 |
| RESTful | 资源+HTTP方法 |
8.2 最佳实践 #
| 实践 | 说明 |
|---|---|
| 模块化 | 按功能模块组织路由 |
| 版本管理 | 使用分组管理API版本 |
| 中间件分层 | 全局、分组、路由级别 |
| RESTful规范 | 遵循REST设计原则 |
8.3 下一步 #
现在你已经掌握了路由分组,接下来让我们学习 HTTP方法,深入了解HTTP方法的使用!
最后更新:2026-03-28