路由分组 #

一、路由分组概述 #

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