Gin路由系统 #
Gin的路由系统基于httprouter,经过优化后的性能是原生Go HTTP路由的40倍,是Echo等其他框架的2倍以上。Gin路由系统的主要特点包括:
- 基于Trie树(前缀树/字典树)实现的高效路由匹配
- 支持RESTful API设计
- 灵活的路由分组机制
- 支持路径参数和通配符
路由注册方式 #
Gin提供了多种路由注册方式,对应HTTP的各种方法:
// GET请求路由
router.GET("/path", HandlerFunc)
// POST请求路由
router.POST("/path", HandlerFunc)
// PUT请求路由
router.PUT("/path", HandlerFunc)
// DELETE请求路由
router.DELETE("/path", HandlerFunc)
// 任意HTTP方法
router.Any("/path", HandlerFunc)
// 自定义HTTP方法
router.Handle("OPTIONS", "/path", HandlerFunc)
路径参数 #
Gin支持在路由路径中定义参数,使用:前缀标识:
router.GET("/user/:id", func(c *gin.Context) {
id := c.Param("id")
c.JSON(200, gin.H{"id": id})
})
通配符路由 #
Gin支持通配符路由,使用*来匹配任意内容:
// 匹配 /user/john/send
// 匹配 /user/john/123/send
router.GET("/user/:name/*action", func(c *gin.Context) {
name := c.Param("name")
action := c.Param("action")
c.String(200, "name: %s, action: %s", name, action)
})
路由分组 #
路由分组是将相关的路由按照功能、资源类型或访问权限等因素组织在一起的一种方式。Gin的路由分组功能允许开发者:
- 为一组相关的路由定义共同的URL前缀
- 为一组路由应用相同的中间件
- 将路由组织成层次结构,提高代码的可读性和可维护性
路由分组在底层实现上,每个分组都是一个RouterGroup实例,它包含了前缀信息、中间件列表以及对父分组和引擎的引用,使Gin能够构建出高效的路由树。
路由分组的基本语法 #
在Gin中创建路由分组的基本语法如下:
// 创建一个路由分组
group := router.Group("/prefix")
// 在分组上定义路由
group.GET("/path", handlerFunc)
group.POST("/another", anotherHandlerFunc)
也可以使用大括号创建更清晰的分组结构:
userGroup := router.Group("/users")
{
userGroup.GET("", getAllUsers)
userGroup.GET("/:id", getUserByID)
userGroup.POST("", createUser)
userGroup.PUT("/:id", updateUser)
userGroup.DELETE("/:id", deleteUser)
}
中间件继承 #
子分组会继承父分组的中间件,同时也可以添加自己的中间件:
// 主分组及其中间件
api := router.Group("/api")
api.Use(loggerMiddleware())
// 子分组继承父分组中间件,并添加额外中间件
authorized := api.Group("/auth")
authorized.Use(authMiddleware())
// 更深层嵌套,继承所有上层中间件,并添加自己的中间件
admin := authorized.Group("/admin")
admin.Use(adminMiddleware())
在这个例子中,对/api/auth/admin路径的访问将会依次通过loggerMiddleware、authMiddleware和adminMiddleware。
实用技巧 #
高效管理大型项目中的路由 #
路由模块化 #
在大型项目中,应该将路由定义从主文件中分离出来,实现模块化。
1、编写各模块对应的业务代码,并暴露出一个方法用来注册路由,例如 user 相关业务:
routes/user.go
package routes
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
)
// SetupUserRoutes 注册 user 相关路由
func SetupUserRoutes(engine *gin.Engine) {
group := engine.Group("/user")
group.GET("/list", func(context *gin.Context) {
context.JSON(http.StatusOK, []gin.H{
{"id": 1, "name": "lucy"},
{"id": 2, "name": "tom"},
})
})
group.POST("/update", func(context *gin.Context) {
fmt.Println("TODO user/update")
context.JSON(http.StatusOK, gin.H{
"status": "OK",
})
})
}
2、编写一个统一管理路由的方法,用于统一注册路由
routes/routes.go
package routes
import "github.com/gin-gonic/gin"
// SetupRoutes 注册路由
func SetupRoutes(engine *gin.Engine) {
SetupUserRoutes(engine)
}
3、在主文件中注册路由
main.go
package main
import (
"github.com/gin-gonic/gin"
"ygang.top/gin-demo/routes"
)
func main() {
engine := gin.Default()
// 注册路由
routes.SetupRoutes(engine)
engine.Run()
}
使用结构体统一管理路由配置 #
// 路由配置结构体
type RouteInfo struct {
Method string
Path string
Handler gin.HandlerFunc
Middlewares []gin.HandlerFunc
}
// 注册单个路由
func registerRoute(rg *gin.RouterGroup, route RouteInfo) {
handlers := append(route.Middlewares, route.Handler)
rg.Handle(route.Method, route.Path, handlers...)
}
// 注册一组路由
func registerRoutes(rg *gin.RouterGroup, routes []RouteInfo) {
for _, route := range routes {
registerRoute(rg, route)
}
}
// 使用示例
func setupUserRoutes(rg *gin.RouterGroup) {
users := rg.Group("/users")
userRoutes := []RouteInfo{
{
Method: "GET",
Path: "",
Handler: userController.GetAllUsers,
},
{
Method: "GET",
Path: "/:id",
Handler: userController.GetUser,
},
{
Method: "POST",
Path: "",
Handler: userController.CreateUser,
Middlewares: []gin.HandlerFunc{validateUserMiddleware()},
},
}
registerRoutes(users, userRoutes)
}
中间件作用域控制 #
中间件可能会带来性能开销,因此应该只在必要的路由上应用特定中间件。全局中间件应限制在日志、恢复等必要功能上。
中间件应该应用在尽可能小的作用域内,避免过度使用全局中间件:
// 不推荐:全局应用验证中间件
router.Use(ValidationMiddleware())
// 推荐:仅在需要的路由组上应用验证中间件
postGroup := apiGroup.Group("/posts")
postGroup.Use(ValidationMiddleware())