1. Gin中间件
Gin框架允许开发者在处理请求的过程中,加入用户自己的钩子(Hook)函数。这个钩子函数就叫中间件,中间件适合处理一些公共的业务逻辑,比如登录认证、权限校验、数据分页、记录日志、耗时统计等。
2. 注册中间件
Gin中的中间件必须是一个gin.HandlerFunc
类型。例如我们像下面的代码一样定义一个统计请求耗时的中间件。
package main import ( "github.com/gin-gonic/gin" "time" "log" ) func main() { } // StatCost 是一个统计耗时请求耗时的中间件 func StatCost() gin.HandlerFunc { //HandlerFunc是一个函数类型,函数的参数是Context的指针类型 return func(c *gin.Context) { start := time.Now() c.Set("name", "小王子") // 可以通过c.Set在请求上下文中设置值,后续的处理函数能够取到该值 // 调用该请求的剩余处理程序 c.Next() // 不调用该请求的剩余处理程序 // c.Abort() // 计算耗时 cost := time.Since(start) log.Println(cost) } }
3. 全局注册
Use源码:
Next执行流程:
4. 为某个路由注册中间件
// 给/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!", }) })
5. 为路由组注册中间件
为路由组注册中间件有以下两种写法。
写法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) {...}) ... }
6. 上下文c设置值和取值
7. 中间件注意事项
gin默认中间件
gin.Default()
默认使用了Logger
和Recovery
中间件,其中:
Logger
中间件将日志写入gin.DefaultWriter
,即使配置了GIN_MODE=release
。Recovery
中间件会recover任何panic
。如果有panic的话,会写入500响应码。
如果不想使用上面两个默认的中间件,可以使用gin.New()
新建一个没有任何默认中间件的路由。
gin中间件中使用goroutine
当在中间件或handler
中启动新的goroutine
时,不能使用原始的上下文(c *gin.Context),必须使用其只读副本(c.Copy()
)。
package main import ( "github.com/gin-gonic/gin" "log" ) func main() { r := gin.Default() // async异步 // sync同步 r.GET("/long_async", func(c *gin.Context) { // 创建要在goroutine中使用的副本 cCp := c.Copy() go func() { // 这里使用你创建的副本 log.Println("Done! in path ccp " + cCp.Request.URL.Path) log.Println("Done! in path c " + c.Request.URL.Path) // c是可行的??? log.Println("Done! in path c " + c.Request.Method) // c是可行的??? }() }) r.GET("/long_sync", func(c *gin.Context) { // 这里没有使用goroutine,所以不用使用副本 log.Println("Done! in path " + c.Request.URL.Path) }) r.Run(":8080") }