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