Gin框架允许开发者在处理请求的过程中,加入用户自己的钩子(Hook)函数。这个钩子函数就叫中间件,中间件适合处理一些公共的业务逻辑,比如登录认证、权限校验、数据分页、记录日志、耗时统计等。
简而言之,中间件是用在两个模块之间的功能软件,比如在前后台开发中:
路由 ——> 中间件 (起过滤作用) ——> 控制器
在Gin中,中间件的效果可以简单的概括为:
Gin中的中间件必须是一个gin.HandlerFunc
类型,在自定义中间件函数时,有两种写法:
func Test(c *gin.Context) {
}
// 使用中间件
r.Use(Test)
tuation">}
// 使用中间件
r.Use(Test())
在gin框架中,我们可以为每个路由添加任意数量的中间件。
func main() {
// 新建一个没有任何默认中间件的路由
r := gin.New()
// 注册一个全局中间件
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) {...})
...
}
中间件可以嵌套使用,这里有三个相关的函数。
表示跳过当前中间件剩余内容, 去执行下一个中间件。 当所有操作执行完之后,以出栈的执行顺序返回,执行剩余代码。
// 创建中间件
func Test1(ctx *gin.Context) {
fmt.Println("1111")
ctx.Next()
fmt.Println("4444")
}
// 创建 另外一种格式的中间件.
func Test2() gin.HandlerFunc {
return func(context *gin.Context) {
fmt.Println("3333")
context.Next()
fmt.Println("5555")
}
}
func main() {
router := gin.Default()
// 使用中间件
router.Use(Test1)
router.Use(Test2())
router.GET("/test", func(context *gin.Context) {
fmt.Println("2222")
context.Writer.WriteString("hello world!")
})
router.Run(":9999")
}
终止执行当前中间件剩余内容,执行下一个中间件。 当所有的函数执行结束后,以出栈的顺序执行返回,但,不执行return后的代码。
// 创建中间件
func Test1(ctx *gin.Context) {
fmt.Println("1111")
ctx.Next()
fmt.Println("4444")
}
// 创建 另外一种格式的中间件.
func Test2() gin.HandlerFunc {
return func(context *gin.Context) {
fmt.Println("3333")
return
context.Next()
fmt.Println("5555")
}
}
func main() {
router := gin.Default()
// 使用中间件
router.Use(Test1)
router.Use(Test2())
router.GET("/test", func(context *gin.Context) {
fmt.Println("2222")
context.Writer.WriteString("hello world!")
})
router.Run(":9999")
}
只执行当前中间件, 操作完成后,以出栈的顺序,依次返回上一级中间件。
// 创建中间件
func Test1(ctx *gin.Context) {
fmt.Println("1111")
ctx.Next()
fmt.Println("4444")
}
// 创建 另外一种格式的中间件.
func Test2() gin.HandlerFunc {
return func(context *gin.Context) {
fmt.Println("3333")
context.Abort()
fmt.Println("5555")
}
}
func main() {
router := gin.Default()
// 使用中间件
router.Use(Test1)
router.Use(Test2())
router.GET("/test", func(context *gin.Context) {
fmt.Println("2222")
context.Writer.WriteString("hello world!")
})
router.Run(":9999")
}
gin.Default()默认使用了Logger和Recovery中间件,其中:
如果不想使用上面两个默认的中间件,可以使用gin.New()新建一个没有任何默认中间件的路由。
当在中间件或handler中启动新的goroutine时,不能使用原始的上下文(c *gin.Context),必须使用其只读副本(c.Copy())
参考资料:
网站声明:如果转载,请联系本站管理员。否则一切后果自行承担。
加入交流群
请使用微信扫一扫!