25-中间件

4 阅读2分钟

中间件

  • 可以配置多个中间件
  • 执行顺序类似 koa 的洋葱模型

例子1

  • 路由中间件: 针对某个路由设置的中间件
package main

import (
    "fmt"
    "github.com/gin-gonic/gin"
)

func initWare(c *gin.Context) {
    fmt.Println("中间件1")
    c.Next()
    fmt.Println("中间件2")
}

func main() {
    r := gin.Default()
    
    //=> 可以配置多个中间件
    r.GET("/home", initWare, func(c *gin.Context) {
        c.String(200, "home")
    })
    
    r.Run()
}

例子2

  • 全局中间件: 每个路由都需要先经过它
    • 比如是否登录了鉴权
package main

import (
    "fmt"
    "github.com/gin-gonic/gin"
)

func initWare1(c *gin.Context) {
    fmt.Println("全局中间件1,每个路由都需要先经过它")
    c.Next()
}
func initWare2(c *gin.Context) {
    fmt.Println("全局中间件2,每个路由都需要先经过它")
    c.Next()
}
func main() {
    r := gin.Default()
    
    //=> 可以配置多个中间件
    r.Use(initWare1, initWare2)
    
    r.GET("/home", func(c *gin.Context) {
        c.String(200, "home")
    })
    
    r.Run()
}

例子3

  • 路由分组中间件: 针对特定的路由集群设置的中间件
  • 中间件的设值控制器的配合使用
  • 中间件和中间件之间也是可以的
package main

import (
    "fmt"
    "github.com/gin-gonic/gin"
)

func initWare1(c *gin.Context) {
    fmt.Println("路由分组中间件1")
    c.Set("username", "张三")//设置共享数据
    c.Next()
}
func initWare2(c *gin.Context) {
    fmt.Println("路由分组中间件2")
    c.Next()
}
func main() {
    r := gin.Default()
    
    //=> 可以配置多个中间件 方式1
    adminRouter := r.Group("/admin", initWare1, initWare2)
    {
        r.GET("/", func(c *gin.Context) {
            c.String(200, "admin-home")
        })
        r.GET("/news", func(c *gin.Context) {
            username, _ := c.Get("username")//获取数据
            v, ok := username.(string)
            if ok == true {
               c.String(200, "admin-news-%v", username)
            }else {
                c.String(200, "获取页面失败")
            }
        })
    }
    
    frontRouter := r.Group("/front")
    frontRouter.Use(initWare1, initWare2)//=> 方式二
    {
        r.GET("/", func(c *gin.Context) {
            c.String(200, "admin-home")
        })
        r.GET("/news", func(c *gin.Context) {
            c.String(200, "admin-news")
        })
    }
    
    r.GET("/home", func(c *gin.Context) {
        c.String(200, "home")
    })
    
    r.Run()
}

中间件的注意事项

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())
r.GET("/", func (c *gin.Context) {
    cCp := c.Copy()
    
    go func() {
       time.Sleep(4 * time.Second)
       
       // 创建副本
       fmt.Println("do something" + cCp.Request.URL.Path)
    }()
    c.String(200, "这是首页")
})

就是你需要提前处理事务,或者分步骤去处理事务的时候,可以选择中间件