这是我参与「第五届青训营」伴学笔记创作活动的第 16 天
定义中间件
Gin框架允许开发者在处理请求的过程中,加入用户自己的钩子(Hook)函数。这个钩子函数就叫中间件,中间件适合处理一些公共的业务逻辑,比如登录认证、权限校验、数据分页、记录日志、耗时统计等。
Gin中的中间件必须是一个 gin.HandlerFunc 类型。
下面是一个简单的中间件,用来计算耗时
func middle(c *gin.Context) {
start := time.Now()
c.Next() // 调用后续的处理函数
cost := time.Since(start)
fmt.Println("time: ", cost)
}
Next 继续后面的处理函数
Abort 阻止后续的处理函数
可以看出,go的中间件就是一个钩子函数。仔细观察可以发现,中间件和处理请求时的处理函数相似。
查看 get 源码
可以很清晰的看出,使用的处理函数本质就是中间件。这里又不得不感慨 go 的简洁。
注册中间件
路由注册
由源码可以看出,中间件参数是一个不定参数,所以直接填入即可。
r.GET("/", middle, func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"message": "Hello World"})
})
路由组注册
查看 gin 路由组的源码,可以看出和 GET 的是一样的。故注册方式一样
userGroup := r.Group("/user", middle)
全局注册
全局注册要使用 Use 函数
r.Use(middle)
查看 use 的源码
同样的不定参数,同样的味道。
中间件原理
学会了定义和注册就可以完成基本的使用了,有的小伙伴可能就会有疑问,中间件的执行顺序是什么样子,下面我们就来看看。
中间件会按照添加顺序执行。流程入下图
gin 的中间件维护了一个 HandlerChain 函数数组和一个索引 index。每增加一个中间件就 index++。
用户验证登录案例
func AuthMiddleWare() gin.HandlerFunc {
return func(c *gin.Context) {
cookie, err := c.Cookie("session_id") // 获取cookie
if err != nil || cookie == "" {
c.JSON(401, gin.H{"error": "未登录"})
c.Abort() // 中断请求
return
}
c.Next() // 继续请求
}
}