Gin中间件(重要)
Gin框架允许开发者在处理请求的过程中,加入用户自己的钩子(Hook)函数。
这个钩子函数就叫中间件,中间件适合处理一些公共的业务逻辑,比如登录校验、日志打印、耗时统计等。
例子:中间件
package main import ( "fmt" "github.com/gin-gonic/gin" "net/http" "time" ) func indexHandler(c *gin.Context){ fmt.Println("index") name, ok := c.GET("name") if !ok { name = "匿名用户" } c.JSON(http.StatusOK, gin.H{ "msg": name, }) } func m1(c *gin.Context){ fmt.Println("m1 in...") start := time.Now() c.Next() // 调用后续的处理函数 cost := time.Since(start) fmt.Printf("cost:%v\n", cost) fmt.Println("m1 out...") } func m2(c *gin.Context){ fmt.Println("m2 in...") c.set("name", "qimi") // m1里做一些操作,m2里拿到 // return // 到这里直接退出,不会打印出m2 out... fmt.Println("m2 out...") } func authMiddleware(doCheck bool)gin.HandlerFunc{ // 或这些其他准备工作 return func(c *gin.Context){ if doCheck { // 是否登录的判断 // c.Next() // c.Abort() } else { c.Next() } } } func main(){ r := gin.Default() // 默认使用Logger()和Recovrey() r.Use(m1, m2, authMiddleware(true)) // 全局注册中间件函数 m1 m2 r.GET("/index", indexHandler) r.GET("/shop", func(c *gin.Context){ c.JSON(http.StatusOK, gin.H{ "msg": "index", }) }) r.GET("/user", func(c *gin.Context){ c.JSON(http.StatusOK, gin.H{ "msg":"index ", }) }) /* (全局已经注册) xxGroup := r.Group("/xx", authMiddleware(true)) { xx.Group.GET("/index", func(c *gin.Context){ c.JSON(http.StatusOK, gin.H{"msg": "xxGroup"}) }) } xx2Group := r.Group("/xx2") xx2Group.Use(authMiddleware(true)) { xx2Group.Get("/index", func(c *gin.Context){ c.JSON(http.StatusOK, fin.H{"msg": "xx2Group"}) }) } */ r.Run() // :8080 }
定义中间件
Gin的中间件必须是一个gin.HandlerFunc类型。例如下面代码一样:定义一个中间件。
// StatCost 是一个统计耗时请求耗时的中间件 func StatCost() gin.HandlerFunc { return func (c *gin.Context) { start := time.Now() c.Set("name", "小王子") c.Next() // c.Abort() cost := time.Since(start) log.Println(cost) } }
注册中间件
在gin框架中,可以为每个路由添加任意数量的中间件。
为全局路由注册
func main(){ // 注册一个全局中间件 r.Use(StatCost()) r.Get("/test", func(c *gin.Context){ name := c.MustGet("name").(string) // 从上下文取值 log.Println(name) c.JSON(http.StatusOK, gin.H{ "message": "Hello world!" }) }) r.Run() }
为某个路由单独注册
// 给/test2路由单独注册中间件(可注册多个) r.GET("/test2", StatCost(), func(c *gin.Context){ name := c.MustGet("name").(string) // 从上下文取值 log.Println(name) c.JSON(http.StatusOK, gin.H{ "message": "Hello world!", }) })
为路由组注册中间件
写法1:
shopGroup := r.Group("/shop", StatCost()) { shopGroup.GET("/index", func(c *gin.Context){...}) ... }
写法2:
shopGroup := r.Group("/shop") shopGroup.Use(StatCost()) { shopGroup.GET("/index", func(c *gin.Context){...}) ... }
中间件注意事项
gin默认中间件件
Gin.Default()默认使用了Logger 和 Recovery 中间件,其中:
Logger中间件将日志写入gin.DefaultWriter,即使配置了GIN_MODE = release
Recovery 中间件会revover任何panic。如果有panic的话,会写入500响应码。
如果不想使用上面两个默认的中间件,可以使用gin.New()新建一个没有任何默认中间件的路由
gin中间件中使用goroutine
当在中间件或handler中启动新的goroutine时,不能使用原始的上下文(c *gin.Context),必须使用其只读副本(c.Copy())。
例如:
func m1(c *gin.Context){ go funcXX(c.Copy()) }