go web gin 框架 中间件的学习和使用

 
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
 ", 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 退出 

  

原文地址:https://www.cnblogs.com/zexin88/p/14452873.html