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")
}