Gin 中间件的配置方式有许多种,大致为:
- 在
Handle()
、Any()
、Match()
、GET()
等基本路由方法中配置HandlerFunc
。 - 在
RouterGroup
的Group()
方法中配置HandlerFunc
。 - 使用
Use()
方法配置HandlerFunc
。
特定请求的中间件
为特定请求配置中间件,可以直接在请求路由的 HandlerFunc
参数中配置。例如:
-
controllers/user
:type userController struct{} var UserController userController func (userController) GetUser(ctx *gin.Context) { id := ctx.Param("id") // 获取 Context 内部字典的值 token, exists := ctx.Get(middlewares.TOKEN) if !exists { ctx.JSON(http.StatusBadRequest, gin.H{"error": "Unauthorized..."}) } ctx.PureJSON(http.StatusOK, gin.H{ "id": id, "username": "zhangsan", "token": token, }) }
-
middlewares/user
:type userMiddlewares struct{} var UserMiddlewares userMiddlewares const Authorization = "Authorization" func (userMiddlewares) VerifyToken(ctx *gin.Context) { auth := strings.TrimSpace(ctx.GetHeader(Authorization)) if auth == "Bearer 123456" { // 使用 Context.Set() 设置键值对 // 这个键值对只能在当前处理链中按顺序流转 // 换句话说,这个键值对只是存储在当前 Context 中 ctx.Set(TOKEN, "123456") ctx.Next() } else { ctx.JSON(http.StatusBadRequest, gin.H{"error": "Unauthorized..."}) ctx.Abort() } }
中间件也可专门为其定义一个
middlewares
包来存放项目中所有的中间件。处理链:即一组按顺序执行的中间件和处理函数。
-
routers/user.go
:将中间函数和处理函数绑定到路由上:
func UserRoutersInit(engin *gin.Engine) { engin.Group("/user", middlewares.UserMiddleware). GET("/:id", middlewares.UserMiddlewares.VerifyToken, controllers.UserController.GetUser) }
全局中间件
全局中间件就是绑定在根路由上的、全局生效的中间件,可以使用 RouterGroup.Use()
方法绑定全局中间件。例如:
func Router() (engine *gin.Engine) {
engine = gin.Default()
// 设置全局中间件
engine.Use(middlewares.GlobalMiddlewares.VerifyToken)
// ...
}
如果需要绑定的中间件过多,除了多次调用 User()
方法绑定或在 User()
方法中传入多个中间件外,还能使用 gin.HandlersChain
类型。gin.HandlersChain
的定义如下:
type HandlersChain []HandlerFunc
使用 gin.HandlersChain
来聚集多个中间件,然后将它们一次性传入 User()
中:
var globalMiddlewares = gin.HandlersChain{
middlewares.GlobalMiddlewares.VerifyToken,
middlewares.GlobalMiddlewares.VerifyAuthorization,
// ...
}
func Router() (engine *gin.Engine) {
engine = gin.Default()
// 设置全局中间件
engine.Use(globalMiddlewares...)
// ...
}
通过使用 gin.HandlersChain
聚集并注册全局中间件后,中间函数的执行顺序将按照 gin.HandlersChain
中的顺序执行。
分组中间件
分组中间件同样可以使用 RouterGroup.Use()
方法,不同的是调用方法的对象是具体的路由分组对象,也就是 Engin.Group()
调用之后返回的对象。例如:
engin.Group("/user").
Use(middlewares.UserMiddlewares.VerifyToken)
除了使用 RouterGroup.Use()
方法,分组中间件还可以在 Engin.Group()
调用的时候注册。例如:
engin.Group("/user", middlewares.UserMiddlewares.VerifyToken)
同样地,也可以使用 gin.HandlersChain
:
var groupMiddlewares = gin.HandlersChain{
middlewares.UserMiddlewares.VerifyToken,
// ...
}
engin.Group("/user", ...groupMiddlewares)
注:
User()
方法注册的中间件,和使用其它路由方法(如Handle()
、Any()
、GET()
、Match()
等等)注册的中间件、处理函数它们之间的调用顺序也是按照注册的顺序执行。例如:engin.Group("/user", middlewares.UserMiddlewares.VerifyToken). GET("/info/:username", controllers.UserController.GetInfo). POST("/list", controllers.UserController.GetList). // 在此之前的路由,在执行时不会调用 middlewares.UserMiddlewares.VerifyAuthorization // 只会调用 middlewares.UserMiddlewares.VerifyToken Use(middlewares.UserMiddlewares.VerifyAuthorization). // 在此之前的路由,在执行时会按顺序调用 middlewares.UserMiddlewares.VerifyToken // 和 middlewares.UserMiddlewares.VerifyAuthorization GET("/:id", controllers.UserController.GetUser)
中间件 Context
在中间件中,Context
有一些方法可用于中间件的编写:
-
Context.Next()
:将控制权传递给下一个中间件或处理函数。func MyMiddleware(c *gin.Context) { // 执行某些预处理逻辑 c.Next() // 执行某些后处理逻辑 }
-
Context.Abort()
:立即停止执行后续的中间件和处理函数,可以用来处理错误或特殊请求。func ErrorMiddleware(c *gin.Context) { if c.Query("error") == "true" { c.Abort() // 停止执行后续的中间件和处理函数 } else { c.Next() } }
-
Context.Set()
和Context.Get()
:在当前请求处理链中存储和检索数据,允许在处理链中不同的中间件和处理函数之间共享信息。func StoreDataMiddleware(c *gin.Context) { // 存储数据 c.Set("user_id", 123) c.Next() } func RetrieveDataMiddleware(c *gin.Context) { // 获取数据 userId, err := c.Get("user_id") // 使用 userId ... }
`Context.Set()` 和 `Context.Get()` 存储和获取的数据,是存储在当前 `Context` 对象的内部字典(`store` 字段)中。在 Gin 中,对于一条处理链中所有的中间件和处理函数共享同一个 `Context` 对象。
Contex
中除了上述的 4 个方法外,还有其它可以用于控制中间件或处理函数执行流的方法。例如以Abort
开头的Abort
系方法,它们在终止执行链执行的同时,还提供了其它一些额外的操作。比如说Context.AbortWithStatus()
,在中止执行链的同时设置响应状态码。
评论