在Gin的整个实现中,中间件可谓是Gin的精髓。一个个中间件组成一条中间件链,对HTTP Request请求进行拦截处理,实现了代码的解耦和分离,并且中间件之间相互不用感知到,每个中间件只需要处理自己需要处理的事情即可。今天我们就通过这篇文章,详细的介绍Gin中间的使用和原理。

通过这篇文章你可以学到:

  1. Gin中间件入门

  2. 如何使用Gin的默认中间件

  3. 中间件实现HTTP Basic Authorization

  4. 基于分组路由的中间件控制

  5. 自定义一个统计耗时的中间件

  6. 中间件的设计模式-责任链

  7. 自己实现一个责任链模式

  8. 中间件Next方法的实现原理

  9. Gin中间件源码分析

  10. Gin中间件面试要点

开篇前推荐下这篇同样6000字大章的技术变现文章 Go爬虫+WordPress每月躺赚上千元(合法合规实战)

Gin默认中间件

*Engine
r := gin.Default()
Defaultpainc
func Default() *Engine {
    debugPrintWARNINGDefault()
    engine := New()
    engine.Use(Logger(), Recovery())
    return engine
}
Use
func (engine *Engine) Use(middleware ...HandlerFunc) IRoutes
HandlerFunc
r.GET("/", func(c *gin.Context) {
        fmt.Println("首页")
        c.JSON(200, "")
    })
func(c *gin.Context)HandlerFunc

中间件实现HTTP Basic Authorization

HTTP Basic Authorization 是HTTP常用的认证方案,它通过Authorization 请求消息头含有服务器用于验证用户代理身份的凭证,格式为:

Authorization: Basic <credentials>

如果认证不成功,服务器返回401 Unauthorized 状态码以及WWW-Authenticate 消息头,让客户端输入用户名和密码进一步认证。

gin.BasicAuth
    r := gin.Default()

    r.Use(gin.BasicAuth(gin.Accounts{
        "admin": "123456",
    }))

    r.GET("/", func(c *gin.Context) {
        c.JSON(200, "首页")
    })

    r.Run(":8080")
admin123456http://localhost:8080/首页

针对特定URL的Basic Authorization

其实在实际的项目开发中,我们基本上不太可能对所有的URL都进行认证的,一般只有一些需要认证访问的数据才需要认证,比如网站的后台,那么这时候我们就可以用分组路由来处理。

func main() {
    r := gin.Default()

    r.GET("/", func(c *gin.Context) {
        c.JSON(200, "首页")
    })

    adminGroup := r.Group("/admin")
    adminGroup.Use(gin.BasicAuth(gin.Accounts{
        "admin": "123456",
    }))

    adminGroup.GET("/index", func(c *gin.Context) {
        c.JSON(200, "后台首页")
    })

    r.Run(":8080")
}
//admin/index/admin/*/admin

通过分组路由的控制,我们可以比较灵活的设置HTTP认证,粒度可以自己随意控制。

自定义中间件

HandlerFuncHandlerFunc
func costTime() gin.HandlerFunc {
    return func(c *gin.Context) {
        //请求前获取当前时间
        nowTime := time.Now()

        //请求处理
        c.Next()

        //处理后获取消耗时间
        costTime := time.Since(nowTime)
        url := c.Request.URL.String()
        fmt.Printf("the request URL %s cost %v\n", url, costTime)
    }
}
c.Nextc.Next

有了自定义的中间件,我们就可以这么使用。

func main() {
    r := gin.New()

    r.Use(costTime())

    r.GET("/", func(c *gin.Context) {
        c.JSON(200, "首页")
    })

    r.Run(":8080")
}

现在启动程序,在浏览器里打开就可以看到如下日志信息了。

the request URL / cost 26.533µs

通过自定义中间件,我们可以很方便的拦截请求,来做一些我们需要做的事情,比如日志记录、授权校验、各种过滤等等。

责任链模式

在讲Gin的中间件的原理之前,我们先了解下设计模式中的责任链模式。顾名思义,责任链模式就是为请求创建一个对象链,对象链上的每个对象都可以依次对请求进行处理,并把处理过的请求传递给下一个对象,生动描述详见下图: