Gin框架允许开发者在处理请求的过程中,加入用户自己的钩子(Hook)函数。这个钩子函数就叫中间件,中间件适合处理一些公共的业务逻辑,比如登录认证、权限校验、数据分页、记录日志、耗时统计 等。
定义中间件
中间件用的还是比较多的,比如,我们创建路由引擎时 r := gin.Default()
就默认了两个中间件。
1
2
3
4
5
6
7
8
|
// 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
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
| func StatCosts(format string) gin.HandlerFunc {
return func(c *gin.Context) {
start := time.Now()
//闭包的用法,内层函数使用外层函数的变量
log.Println(start.Format(format))
c.Set("name", "bowen")
// 调用该请求的剩余处理程序
c.Next()
//计算耗时
cost := time.Since(start)
log.Println(cost)
}
}
|
这是一个统计执行时间的中间件,带有格式化时间的参数。我们为它写一个测试程序,来看一下注册中间件的过程
注册中间件
全局中间件
1
2
3
4
5
6
7
8
9
10
11
12
| // 新建一个没有任何默认中间件的路由
r := gin.New()
// 注册一个全局中间件
r.Use(StatCosts("2006-01-02 15:04:05"))
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()
|
输入请求,http://127.0.0.1:8080/test
可以看到,按照我们传的参数改了时间格式,拿到了中间件里面set的数据,执行了路由函数,打印时间。
注意点
全局注册,不管请求哪个url路径,都会执行这个中间件
为某个路由注册
局部路由注册
局部中间件,我们可以针对不同的url,选择是否需要中间件,及执行哪一个中间件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| func TestLocal(t *testing.T) {
r := gin.Default()
r.GET("/test", StatCosts("2006-01-02 15:04:05"), func(c *gin.Context) {
name := c.MustGet("name").(string)
log.Println(name)
c.JSON(http.StatusOK, gin.H{
"message": "hello world",
})
})
r.GET("/xyz", StatCosts("2006-01-02 15:04:05"), func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"message": "hello xyz",
})
})
r.Run()
}
|
某个路由不用执行中间件
某个路由不执行中间件
比如100个路由,但有一个不需要或者我不想让它去执行中间件,给它一些特殊对待,可以选择跳过 ,只需要在中间件代码里去判断这个路由跳过即可。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| func StatCost() gin.HandlerFunc {
return func(c *gin.Context) {
if c.Request.URL.Path == "/xyz" {
c.Next()
//c.Abort()
return
// abort()终端当前的handlerfunc
}
start := time.Now()
// 闭包的用法,内层函数使用外层函数的变量 format string,可以传参数
//log.Println(start.Format(format))
c.Set("name", "bowen")
// 调用该请求的剩余处理程序
c.Next()
//计算耗时
cost := time.Since(start)
log.Println(cost)
}
}
|
我们启动服务端,再次请求,就不会执行下面的统计执行时间的过程了。
路由组注册中间件
路由组注册中间件
当我们有共同前缀的路径需要注册中间件时,可以使用路由组注册中间件的方式
路由组注册中间件方式1
1
2
3
4
5
| shopGroup := r.Group("/shop", StatCost())
{
shopGroup.GET("/index", func(c *gin.Context) {...})
...
}
|
路由组注册中间件方式2
1
2
3
4
5
6
| shopGroup := r.Group("/shop")
shopGroup.Use(StatCost())
{
shopGroup.GET("/index", func(c *gin.Context) {...})
...
}
|
iris中间件引用
iris中间件引用
这是群里在讨论时发出来的iris框架中间件的代码,iris在国内公司用的不多,放到这里,是与gin的中间件做对比。
小结
中间件是很重要的一部分,后面会结合实际例子实践,把gin里面学过的基础demo结合和gorm,zap等,当这些看似简单的知识点组合起来的时候,就是一个简单的项目了。再复杂的项目,都是由一个个小的知识点积累起来的。框架本身没什么难的,是手写框架!可以帮我们更深的理解。
- 单个知识点,理解小demo
- 组合其他知识点做综合一点的项目
- 手写中间件框架,理解设计原理