Gin框架系列之中间件

Posted iveBoy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Gin框架系列之中间件相关的知识,希望对你有一定的参考价值。

一、Gin中间件基础

中间件可以实现在整个请求或者响应的生命周期过程中对请求或者响应做一些额外的处理,比如说在每个请求进入路由匹配、函数处理前进行权限校验,避免在业务函数中进行处理,非常方便。那么在Gin中是如何做的呢?

...
router := gin.Default()
...

在gin中的Default的方法中已经有两个中间件了:

// Default returns an Engine instance with the Logger and Recovery middleware already attached.
func Default() *Engine 
    debugPrintWARNINGDefault()
    engine := New()
    engine.Use(Logger(), Recovery())// 日志和异常恢复中间件
    return engine

如果我们想创建一个没有任何中件的router可以通过New方法:

router := gin.New()

 然后可以在这个router中使用中间件:

func main() 
    // 创建一个不包含中间件的路由器
    r := gin.New()

    // 全局中间件
    // 使用 Logger 中间件
    r.Use(gin.Logger())

    // 使用 Recovery 中间件
    r.Use(gin.Recovery())

    // 路由添加中间件,可以添加任意多个
    r.GET("/benchmark", MyBenchLogger(), benchEndpoint)

    // 路由组中添加中间件
    // authorized := r.Group("/", AuthRequired())
    // exactly the same as:
    authorized := r.Group("/")
    // per group middleware! in this case we use the custom created
    // AuthRequired() middleware just in the "authorized" group.
    authorized.Use(AuthRequired())
    
        authorized.POST("/login", loginEndpoint)
        authorized.POST("/submit", submitEndpoint)
        authorized.POST("/read", readEndpoint)

        // nested group
        testing := authorized.Group("testing")
        testing.GET("/analytics", analyticsEndpoint)
    

    // Listen and serve on 0.0.0.0:8080
    r.Run(":8080")

二、自定义中间件

1、实例应用

package main

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

func Logger() gin.HandlerFunc 
    return func(c *gin.Context) 
        // 该中间件中的业务处理
        fmt.Println("日志记录")
        // 请求前
        c.Next() // 处理请求,包括处理后续的中间件
        // 请求后
    


func main() 
    router := gin.New()
    router.Use(Logger())
    router.GET("/welcome", func(c *gin.Context) 
        c.JSON(http.StatusOK, gin.H
            "Name": "bily",
        )
    )
    router.Run(":8000")

2、c.Next()

在上述自定义中间件中中存在Next方法,它是处理请求,如果需要终止该请求后续的逻辑,必须通过c.Abort()方法来终止:

...
func Logger() gin.HandlerFunc 
    return func(c *gin.Context) 
        // 该中间件中的业务处理
        fmt.Println("日志记录")
        c.Abort() // 终止请求的后续逻辑
    

...

那么为什么不能使用return来解决?

在源码中可以看到中间件是放入到一个切片group.Handlers中:

router.Use(Logger())
...
engine.RouterGroup.Use(middleware...)
...
func (group *RouterGroup) Use(middleware ...HandlerFunc) IRoutes 
    group.Handlers = append(group.Handlers, middleware...)
    return group.returnObj()

...

然后在看一下GET请求中的业务函数也是放入这个切片中:

...
router.GET("/welcome", func(c *gin.Context) 
        c.JSON(http.StatusOK, gin.H
            "Name": "bily",
        )
    )
...
func (group *RouterGroup) GET(relativePath string, handlers ...HandlerFunc) IRoutes 
    return group.handle(http.MethodGet, relativePath, handlers)

...
func (group *RouterGroup) handle(httpMethod, relativePath string, handlers HandlersChain) IRoutes 
    absolutePath := group.calculateAbsolutePath(relativePath)
    handlers = group.combineHandlers(handlers)
    group.engine.addRoute(httpMethod, absolutePath, handlers)
    return group.returnObj()

...

所以整个结构如下:

所以如果在Logger中通过return并不能终止指针向后移动,继续指向后面的中间件或者业务函数执行;如果通过Abort函数:

...
func (c *Context) Abort() 
    c.index = abortIndex

...
const abortIndex int8 = math.MaxInt8 / 2
...

可以看到Abort方法是将指针移动到一个很大的数字,这样就没有被指向的中间件或者函数。所以就被终止了。

 

 

作者:iveBoy
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须在文章页面给出原文连接,否则保留追究法律责任的权利。

以上是关于Gin框架系列之中间件的主要内容,如果未能解决你的问题,请参考以下文章

Gin框架系列01:极速上手

Gin框架系列01:极速上手

Gin框架系列之路由分组

Gin框架使用通用http.Handler中間件

Gin框架使用通用http.Handler中間件

Gin框架使用通用http.Handler中間件