中间件(英语:Middleware
),又译中间件、中介层,是一类提供系统软件和应用软件之间连接、便于软件各部件之间的沟通的软件,应用软件可以借助中间件在不同的技术架构之间共享信息与资源。
1.介绍
在Gin
框架中,中间件本质上是gin.HandlerFunc 函数
,如果我们要自定义中间件,只需要返回类型是gin.HandlerFunc
即可。
在Gin
框架中,使用中间件可分为以下几种场景:
2.使用
2.1 全局使用
在gin.Default()
函数中,默认注册全局中间件Logger、Recovery
,具体代码如下:
1 2 3 4 5 6 7 8 9
| func Default() *Engine { debugPrintWARNINGDefault() engine := New() engine.Use(Logger(), Recovery()) return engine }
|
2.2 单个路由使用
1 2 3 4 5 6 7 8 9 10 11 12
| func main() { engine := gin.New() engine.GET("/route",gin.Logger(), func(context *gin.Context) { context.JSON(200,gin.H{"msg":"针对单个路由"}) }) engine.GET("/route2",gin.Logger(),gin.Recovery(), func(context *gin.Context) { context.JSON(200,gin.H{"msg":"针对单个路由添加多个中间件"}) }) _ = engine.Run() }
|
2.3 路由组使用
1 2 3 4 5 6 7 8 9 10 11
| func main() { engine := gin.New() v1Group := engine.Group("/v1").Use(gin.Logger()) { v1Group.GET("/middleGroup", func(context *gin.Context) { context.JSON(200,gin.H{"msg":"succss"}) }) } _ = engine.Run() }
|
3.自定义中间件
我们可以创建自己的中间件,在中间件中需要继续执行时,使用c.Next()
,而要终止执行时则需调用c.Abort()
终止请求。
3.1 语法结构
1 2 3 4 5 6 7 8 9 10 11
| func MiddleName() gin.HandlerFunc { return func(context *gin.Context) { context.Next() end := time.Now().Unix() fmt.Printf("接口耗时:%v 秒 \n", end - t) } }
|
代码说明:
MiddleName
: 自定义中间件名称。
gin.HandlerFunc
: 中间件始终返回这个类型。
func(context *gin.Context)
: 匿名函数,参数是上下文(context *gin.Context
)
context.Next()
: 继续执行调用这个函数。
context.Abort()
:终止执行调用这个函数。
3.2 示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| func MyMiddleware() gin.HandlerFunc { return func(context *gin.Context) { fmt.Println("中间件-- 请求前") t := time.Now().Unix() context.Next() end := time.Now().Unix() fmt.Printf("接口耗时:%v 秒 \n", end - t) } }
func RunWithMyMiddle() { engine := gin.New() engine.GET("/route",MyMiddleware(), func(context *gin.Context) { time.Sleep(time.Second * 3) context.JSON(200,gin.H{"msg":"自定义路由"}) }) _ = engine.Run() }
|
4.多个中间件
如果同时注册多个中间件,那么他们之间的执行顺序是什么样呢?
4.1 执行流程
4.2 代码示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| func MyMiddleware() gin.HandlerFunc { return func(context *gin.Context) { fmt.Println("中间件1-- 请求前") context.Next() fmt.Println("中间件1-- 请求后") } }
func MyMiddleware2() gin.HandlerFunc { return func(context *gin.Context) { fmt.Println("中间件2-- 请求前") context.Next() fmt.Println("中间件2-- 请求后") } }
func main() { engine := gin.New() engine.GET("/route",MyMiddleware(), MyMiddleware2(),func(context *gin.Context) { time.Sleep(time.Second * 3) context.JSON(200,gin.H{"msg":"自定义路由"}) }) _ = engine.Run() }
|
请求控制台输出:
1 2 3 4
| 中间件1-- 请求前 中间件2-- 请求前 中间件2-- 请求后 中间件1-- 请求后
|
5.实践
创建自定义中间件用来判断Token
是否有效(是否是登录状态)。
5.1 源码
./mian.go
代码:
1 2 3 4 5
| package main import "go-use/practise" func main() { practise.RunServeWithCheckToken() }
|
./practise/check_token.go
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| package practise import ( "github.com/gin-gonic/gin" )
func CheckTokenMiddle() gin.HandlerFunc { return func(context *gin.Context) { token := context.DefaultQuery("token","") if token != "abcd" { context.JSON(500,gin.H{"msg":"请先登录!"}) context.Abort() } context.Next() } }
func RunServeWithCheckToken() { engine := gin.Default() engine.GET("/user/login", func(context *gin.Context) { context.JSON(200,gin.H{"msg":"登录成功!","token":"abcd"}) }) user := engine.Group("/user").Use(CheckTokenMiddle()) { user.GET("/info", func(context *gin.Context) { data := map[string]interface{} { "name": "张三", "age": 18, "likes": []string{"打游戏","旅游"}, } context.JSON(200,gin.H{"msg":"请求成功","data":data}) }) user.GET("/update", func(context *gin.Context) { context.JSON(200,gin.H{"msg":"请求成功"}) }) } _ = engine.Run() }
|
5.2 请求
1 2 3 4 5 6 7 8 9
| [lepeng@centos ~] {"msg":"登录成功!","token":"abcd"}
[lepeng@centos ~] {"msg":"请先登录!"}
➜ curl -X GET http://127.0.0.1:8080/user/info?token=abcd {"data":{"age":18,"likes":["打游戏","旅游"],"name":"张三"},"msg":"请求成功"}
|
6.使用Goroutine
当在中间件或 handler
中启动新的 Goroutine
时,不能使用原始的上下文,必须使用只读副本。
6.1 代码示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| func main() { engine := gin.Default() engine.Use(MyMiddleWithGoRoutine()) engine.GET("/useGo", func(context *gin.Context) { context.JSON(200,gin.H{"msg":"success"}) }) _ = engine.Run() }
func MyMiddleWithGoRoutine() gin.HandlerFunc { return func(context *gin.Context) { cpContext := context.Copy() go func() { time.Sleep(3 * time.Second) fmt.Println(cpContext.Request.URL.Path) }() context.Next() } }
|
7.流行的中间件
在gin-gonic/contrib(https://github.com/gin-gonic/contrib)库中整理很多常用的中间件,可以直接使用,具体中间件有以下: