在Gin的整个实现中,中间件可谓是Gin的精髓。一个个中间件组成一条中间件链,对HTTP Request请求进行拦截处理,实现了代码的解耦和分离,并且中间件之间相互不用感知到,每个中间件只需要处理自己需要处理的事情即可。 Gin中常用的中间件是:
Logger 日志
Recovery panic 处理 返回500
BasicAuth 基本认证
Gin默认中间件
在Gin中,我们可以通过Gin提供的默认函数,来构建一个自带默认中间件的*Engine
。
r := gin.Default()
Default
函数会默认绑定两个已经准备好的中间件,它们就是Logger 和 Recovery,帮助我们打印日志输出和painc
处理。
func Default() *Engine { debugPrintWARNINGDefault() engine := New() engine.Use(Logger(), Recovery()) return engine }
从中我们可以看到,Gin的中间件是通过Use
方法设置的,它接收一个可变参数,所以我们同时可以设置多个中间件。
func (engine *Engine) Use(middleware ...HandlerFunc) IRoutes
到了这里其实我们应该更加明白了,一个Gin的中间件,其实就是Gin定义的一个HandlerFunc
,而它在我们Gin中经常使用,比如:
r.GET("/", func(c *gin.Context) { fmt.Println("首页") c.JSON(200, "") })
后面的func(c *gin.Context)
这部分其实就是一个HandlerFunc
。
在Gin中,为我们提供了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")
我们添加一个用户名为admin
,密码是123456
的账户,用于HTTP 基本认证。现在我们运行启动,访问http://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/*
下的URL都会让输入密码才能访问,这就是我们分组路由的好处,我们通过把中间件加到/admin
这个分组路由上,就可以达到我们的目的。
通过分组路由的控制,我们可以比较灵活的设置HTTP认证,粒度可以自己随意控制。
自定义中间件
我们已经知道,Gin的中间件其实就是一个HandlerFunc
,那么只要我们自己实现一个HandlerFunc
,就可以自定义一个自己的中间件。现在我们以统计每次请求的执行时间为例,来演示如何自定义一个中间件。
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 ", url, costTime) } }
以上我们就实现了一个Gin中间件,比较简单,而且有注释加以说明,这里要注意的是c.Next
方法,这个是执行后续中间件请求处理的意思(含没有执行的中间件和我们定义的GET方法处理),这样我们才能获取执行的耗时。也就是在c.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
通过自定义中间件,我们可以很方便的拦截请求,来做一些我们需要做的事情,比如日志记录、授权校验、各种过滤等等。