Gin框架允许开发者在处理请求的过程中,加入用户自己的钩子(Hook)函数。这个钩子函数就叫中间件,中间件适合处理一些公共的业务逻辑,比如登录认证、权限校验、数据分页、记录日志、耗时统计等。
1 单个路由注册中间件
// 统计耗时 的中间件
func m1(c *gin.Context) {
fmt.Println("m1 in ...")
// 计时
start := time.Now()
c.Next() // 调用后续的处理函数
// c.Abort() // 阻止调用后续的处理函数
cost := time.Since(start)
fmt.Printf("cost:%v\n", cost)
fmt.Println("m1 out ...")
}
func indexHandler(c *gin.Context) {
c.JSON(http.StatusOK, "index")
}
func main() {
r := gin.Default()
r.GET("/index", m1, indexHandler)
r.Run("0.0.0.0:5000")
}
2 全局路由注册中间件
(1) 全局注册中间件函数m1, m2
// 统计耗时 的中间件
func m1(c *gin.Context) {
fmt.Println("m1 in ...")
// 计时
start := time.Now()
c.Next() // 调用后续的一个处理函数
// c.Abort() // 阻止调用后续的所有处理函数
cost := time.Since(start)
fmt.Printf("cost:%v\n", cost)
fmt.Println("m1 out ...")
}
func m2(c *gin.Context) {
fmt.Println("m2 in ...")
c.Next()
fmt.Println("m2 out ...")
}
func indexHandler(c *gin.Context) {
fmt.Println("index")
c.JSON(http.StatusOK, "index")
}
func main() {
r := gin.Default()
r.Use(m1, m2) // 全局注册中间件函数m1, m2
r.GET("/index", indexHandler)
r.Run("0.0.0.0:5000")
}
(2) 闭包
func login_required(doCheck bool) gin.HandlerFunc {
return func(c *gin.Context) {
if doCheck {
// 获取token
// 查询数据库获取user_id
c.Set("user_id", 23)
} else {
c.Next()
}
}
}
func indexHandler(c *gin.Context) {
fmt.Println("index")
user_id, exists := c.Get("user_id")
if !exists {
fmt.Println("user_id不存在")
} else {
fmt.Println("user_id:", user_id)
}
c.JSON(http.StatusOK, "index")
}
func main() {
r := gin.Default()
r.Use(login_required(true))
r.GET("/index", indexHandler)
r.Run("0.0.0.0:5000")
}
3 路由组注册中间件
func login_required(doCheck bool) gin.HandlerFunc {
return func(c *gin.Context) {
if doCheck {
// 获取token
// 查询数据库获取user_id
c.Set("user_id", 23)
} else {
c.Next()
}
}
}
func main() {
r := gin.Default()
fooGroup := r.Group("/foo", login_required(true))
{
fooGroup.GET("/bar", func(c *gin.Context){
user_id, exists := c.Get("user_id")
if !exists {
fmt.Println("user_id不存在")
} else {
fmt.Println("user_id:", user_id)
}
c.JSON(http.StatusOK, "foobar")
})
}
r.Run("0.0.0.0:5000")
}
4 注意事项
gin.Default()默认使用了Logger和Recovery中间件,其中:
- Logger中间件将日志写入gin.DefaultWriter,即使配置了GIN_MODE=release。
- Recovery中间件会recover任何panic。如果有panic的话,会写入500响应码。
如果不想使用上面两个默认的中间件,可以使用gin.New()新建一个没有任何默认中间件的路由。
当在中间件或handler中启动新的goroutine时,不能使用原始的上下文(c *gin.Context),必须使用其只读副本(c.Copy())。