package main import ( "fmt" "github.com/gin-gonic/gin" "net/http" "time" ) type Student struct { Name string `json:"name"` Country string `json:"country"` City string `json:"city"` } // handlerfun 处理函数的格式 /* func (group *RouterGroup) GET(relativePath string, handlers ...HandlerFunc) IRoutes { return group.handle(http.MethodGet, relativePath, handlers) } */ // 自定义中间件 注意: 中间件必须是一个handlerfunc 类型 func Myhandlerfun(c *gin.Context) { fmt.Println("路由函数 start.....") time.Sleep(3) // make this functinon sleep a secent so that we can see the diffirent clearly c.JSON(http.StatusOK, gin.H{ "cotent": "ok", }) } // 自定义中间件: func Mytestmi(c *gin.Context) { fmt.Println("m1 start.....") fmt.Println("---------------this is for middleware test----------") ti := time.Now() c.Next() // 调用后续处理的函数 包括后续的中间件。 所有后续中函数和中间件执行完了 以后, timecost := time.Since(ti) fmt.Printf("处理函数消耗的时间是%v\n ", timecost) fmt.Println("中间件函数 Mytestmi 退出") fmt.Println("m1 stop.....") } // 再定义一个中间件 func m2(c *gin.Context) { fmt.Println("m2 start.....") fmt.Println("--------------m2 test--------------") //c.Abort() //阻止 后续的执行函数操作 查询结果 查询,路由函数正常执行, m3 没有执行。 } // c.Abort() 阻止调用后续的执行函数。 再创建一个中间件,在上一个中间件中 c.Abort() ,然后看下 后续的中间件和 路由执行函数是否有执行。 func m3(c *gin.Context) { fmt.Println("m3 start.....") c.Set("hostname","v_jsonchang") fmt.Println("----------------this is m3 test---------------") fmt.Println("m3 stop.....") } // 是否登录判断的中间件 func authorMiddle(c *gin.Context) { c.Next() c.Abort() /* 大致逻辑思路 if 是用户 c.Next() else c.Abort()0 */ } // 写法 func AuthorCheckMiddle(check bool) gin.HandlerFunc { // 连接数据库 // 或者一些其他的准备工作[这部分在程序运行的时候就执行了] /* 运行程序的时候的日志信息: [GIN-debug] GET /index --> main.Myhandlerfun (4 handlers) [GIN-debug] GET /home --> main.main.func1 (4 handlers) [GIN-debug] GET /student/info --> main.main.func2 (6 handlers) [GIN-debug] POST /student/add --> main.main.func3 (6 handlers) 数据库连接中........ 查找数据库....... 数据正确 用户存在的 [GIN-debug] GET /authtest/test --> main.main.func4 (4 handlers) [GIN-debug] GET /mytest/test --> main.main.func5 (4 handlers) [GIN-debug] GET /mytest --> main.main.func6 (3 handlers) [GIN-debug] Listening and serving HTTP on :8922 */ // 测试例子 fmt.Println("数据库连接中........") fmt.Println("查找数据库.......") fmt.Println("数据正确 用户存在的") /* */ return func(c *gin.Context) { if check { fmt.Println("需要校验") fmt.Println("开始校验-------------") // 存放具体的逻辑 // 是否登录的判断 。。。。 fmt.Println("校验结束-------------") } else { c.Next() } } } func main() { r := gin.Default() //r.Use(Mytestmi) // 全局的中间件 如果想全局设置的话。 r.GET("/index", Mytestmi, Myhandlerfun) // 可以给某个路由 直接添加 写好的中间件,自行添加和去掉,对比输出 结果 // 缺点:加入路由比较多,自己每一个都要加一下, 解决方法: 直接给整体加一个,使用方法: use 函数。 r.GET("/home", Mytestmi, func(c *gin.Context) { time.Sleep(5) // 让程序睡一会 模拟耗时的函数处理 c.JSON(http.StatusOK, gin.H{ "home": "shanxi", "weather": "good", }) /* 没有加中间件的执行日志信息: 日志信息 [GIN-debug] Listening and serving HTTP on :7777 [GIN] 2021/02/26 - 15:29:27 |?[97;42m 200 ?[0m| 994.3µs | 127.0.0.1 |?[97;44m GET ?[0m "/home" [GIN] 2021/02/26 - 15:29:35 |?[97;42m 200 ?[0m| 6.9904ms | 127.0.0.1 |?[97;44m GET ?[0m "/home" 输出: { "home": "shanxi", "weather": "good" } 加了中间件之后,再次执行的日志信息 [GIN] 2021/02/26 - 15:32:09 |?[97;42m 200 ?[0m| 9.9996ms | 127.0.0.1 |?[97;44m GET ?[0m "/home" ---------------this is for middleware test---------- 处理函数消耗的时间是1.0001ms 中间件函数 Mytestmi 退出 */ }) // 创建一个路由分组 进行整体的中间件的使用 studentGroup := r.Group("/student") // studentGroup 分组整体 使用中间件 studentGroup.Use(Mytestmi,m2,m3) // 再添加一个中间件 // 分组路由1 studentGroup.GET("/info", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "school": "深圳大学", "Class": "三年级", "Number": 100, }) }) studentGroup.POST("/add", func(c *gin.Context) { fmt.Println("路由函数 开始.....") //实例化 一个学生结构体 stu := &Student{} // 请求json数据绑定到 结构体 err := c.ShouldBindJSON(&stu) if err != nil { c.JSON(http.StatusInternalServerError,gin.H{ "err": err.Error(), }) } else { c.JSON(http.StatusOK,gin.H{ "result":"ok", "message":"add successful", "Name":stu.Name, "Country":stu.Country, "City":stu.City, }) } fmt.Println("路由函数 结束.....") }) // AuthorCheckMiddle 测试 authtest := r.Group("/authtest") authtest.Use(AuthorCheckMiddle(false)) // true 需要校验 false 不需要校验 可以看到输出的变化,打开是有校验的打印信息,关闭是没有走校验 authtest.GET("/test", func(c *gin.Context) { c.JSON(http.StatusOK,gin.H{ "auth":"ok", }) }) /* 加中间件之前 日志没有显示 中间件的信息。 [GIN-debug] Listening and serving HTTP on :8922 [GIN] 2021/02/26 - 16:02:28 |?[97;42m 200 ?[0m| 0s | 127.0.0.1 |?[97;44m GET ?[0m "/student/info" [GIN] 2021/02/26 - 16:02:41 |?[97;42m 200 ?[0m| 0s | 127.0.0.1 |?[97;44m GET ?[0m "/student/info" [GIN] 2021/02/26 - 16:02:42 |?[97;42m 200 ?[0m| 0s | 127.0.0.1 |?[97;44m GET ?[0m "/student/info" [GIN] 2021/02/26 - 16:03:34 |?[90;43m 404 ?[0m| 0s | 127.0.0.1 |?[97;46m POST ?[0m "/student/info" [GIN] 2021/02/26 - 16:03:46 |?[97;41m 500 ?[0m| 0s | 127.0.0.1 |?[97;46m POST ?[0m "/student/add" [GIN] 2021/02/26 - 16:04:40 |?[97;42m 200 ?[0m| 0s | 127.0.0.1 |?[97;46m POST ?[0m "/student/add" [GIN] 2021/02/26 - 16:04:46 |?[97;42m 200 ?[0m| 0s | 127.0.0.1 |?[97;46m POST ?[0m "/student/add" 输出: http://127.0.0.1:8922/student/info get 请求 { "Class": "三年级", "Number": 100, "school": "深圳大学" } http://127.0.0.1:8922/student/add post 请求 { "City": "shenzhen", "Country": "china", "Name": "stefan", "message": "add successful", "result": "ok" } studentGroup.Use(Mytestmi) 使用中间件之后 请求日志: [GIN-debug] Listening and serving HTTP on :8922 ---------------this is for middleware test---------- 处理函数消耗的时间是995.7µs 中间件函数 Mytestmi 退出 [GIN] 2021/02/26 - 16:09:14 |?[97;42m 200 ?[0m| 2.9967ms | 127.0.0.1 |?[97;44m GET ?[0m "/student/info" ---------------this is for middleware test---------- 处理函数消耗的时间是0s 中间件函数 Mytestmi 退出 [GIN] 2021/02/26 - 16:09:34 |?[97;42m 200 ?[0m| 27.0001ms | 127.0.0.1 |?[97;46m POST ?[0m "/student/add" 通过日志可以看出 学生分组路由已经添加了 中间件的函数。 */ //如果想要设置全局的中间件,就直接给 r 设置即可 /* r := gin.Default() r.Use(Mytestmi) use 函数中,中间件 只需要传入函数名字即可,不需要后面的括号 */ testgroup := r.Group("/mytest") testgroup.Use(Mytestmi,m2,m3) testgroup.GET("/test", func(c *gin.Context) { name,ok := c.Get("hostname") // "name" 测试 就是 匿名用户 if ! ok { name = "匿名用户" } else { c.JSON(http.StatusOK,gin.H{ "hostname":name, }) } }) r.GET("/mytest", func(c *gin.Context) { c.JSON(http.StatusOK,gin.H{ "message":"ok", }) }) r.Run(":8922") } /* 请求日志 [GIN] 2021/02/26 - 15:20:13 |?[97;42m 200 ?[0m| 2.9978ms | 127.0.0.1 |?[97;44m GET ?[0m "/index" ---------------this is for middleware test---------- 处理函数消耗的时间是998.1µs 中间件函数 Mytestmi 退出 [GIN] 2021/02/26 - 15:22:27 |?[97;42m 200 ?[0m| 998.1µs | 127.0.0.1 |?[97;44m GET ?[0m "/index" */ /* 添加两个中间件,观察 执行的顺序 日志输出: [GIN-debug] Listening and serving HTTP on :8922 m1 start..... ---------------this is for middleware test---------- m2 start..... --------------m2 test-------------- m2 stop..... 路由函数 开始..... 路由函数 结束..... 处理函数消耗的时间是2.9738ms 中间件函数 Mytestmi 退出 m1 stop..... 执行顺序: 最开始的 进入中间件1--------中间件2.... 中间件3--------- 路由函数------再到中间件1 内部处理 最后中间件1 退出 */
执行流程图
中间件和处理函数的执行流程
[GIN-debug] Listening and serving HTTP on :8922 m1 start..... ---------------this is for middleware test---------- m2 start..... --------------m2 test-------------- m2 stop..... 路由函数 开始..... 路由函数 结束..... 处理函数消耗的时间是2.9738ms 中间件函数 Mytestmi 退出 m1 stop..... 执行顺序: 最开始的 进入中间件1--------中间件2.... 中间件3--------- 路由函数------再到中间件1 内部处理 最后中间件1 退出