gin框架中間件 c.Next() c.Abort() c.Set() c.Get 跨中間件取值 gin中間件中使用goroutine

1. c.Next()演示

//HandlerFunc
func indexHandler(c *gin.Context)  {
	fmt.Println("index")
	c.JSON(http.StatusOK, gin.H{
		"msg": "index",
	})
}

//定義一箇中間件
func m1(c *gin.Context) {
	fmt.Println("m1 in ...")
	// 計時
	start := time.Now()
	c.Next() //調用後續的處理函數

	//c.Abort() //阻止調用後續的處理函數
	cost := time.Since(start)
	fmt.Printf("cost:%v\n", cost)
	fmt.Printf("m1 out ...")
}

func m2(c *gin.Context)  {
	fmt.Println("m2 in ...")
	c.Next()  //調用後續的處理函數
	fmt.Println("m2 out ...")
}

func main()  {
	r := gin.Default()

	//點GET查看源碼發現
	//GET(relativePath string, handlers ...HandlerFunc) IRoutes  另外,...表示 可傳多個HandlerFunc類型的函數

	//r.GET("/index", m1, indexHandler)
	//r.GET("/shop", m1, func(c *gin.Context) {
	//	c.JSON(http.StatusOK, gin.H{
	//		"msg": "shop",
	//	})
	//})
	//r.GET("/user", m1,  func(c *gin.Context) {
	//	c.JSON(http.StatusOK, gin.H{
	//		"msg": "user",
	//	})
	//})

	// 點開Use 查看源碼發現 Use(middleware ...HandlerFunc) IRoutes
	r.Use(m1, m2)   //全局註冊中間件函數m1 m2

	/*訪問/index
	 執行indexHandler之前 去執行註冊的中間件  總的執行打印順序是:m1 in  -> m2 in -> index -> m2 out -> m1 out
	*/
	r.GET("/index", indexHandler)
	r.GET("/shop",  func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"msg": "shop",
		})
	})
	r.GET("/user",  func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"msg": "user",
		})
	})

	r.Run(":9090")
}

執行結果:
在這裏插入圖片描述
執行邏輯:
在這裏插入圖片描述
代碼執行圖解:
在這裏插入圖片描述

2. c.Abort()演示:

上面代碼把m2這裏改成阻止,其他地方不變,如下圖:
在這裏插入圖片描述
此時執行,控制檯打印輸出爲:

m1 in  -> m2 in ->m2 out -> m1 out

代碼執行圖解:
在這裏插入圖片描述
當然,如果連 m2 out 都不想讓它輸出的話,那直接在c.Abort() 語句 後return就可以了,如下圖:
在這裏插入圖片描述

3. c.Set() c.Get 跨中間件取值

//HandlerFunc
func indexHandler(c *gin.Context)  {
	fmt.Println("index")

	name, ok := c.Get("name")  //取值 實現了跨中間件取值
		if !ok{
		name = "default user"
	}

	c.JSON(http.StatusOK, gin.H{
		"msg": name,
	})
}

//定義一箇中間件
func m1(c *gin.Context) {
	fmt.Println("m1 in ...")
	// 計時
	start := time.Now()

	//gin中間件中使用goroutine 
	//當在中間件或handler中啓動新的goroutine時,不能使用原始的上下文(c *gin.Context),必須使用其只讀副本(c.Copy())
	go otherFunc(c.Copy()) // 在otherFunc中只能使用c的拷貝

	c.Next() //調用後續的處理函數

	//c.Abort() //阻止調用後續的處理函數
	cost := time.Since(start)
	fmt.Printf("cost:%v\n", cost)
	fmt.Printf("m1 out ...")
}

func m2(c *gin.Context)  {
	fmt.Println("m2 in ...")

	c.Set("name", "tony")  //可以在請求上下文裏面設置一些值,然後其他地方取值

	c.Abort()  //阻止調用後續的處理函數 也就是 m2它自己走完就行
	//return
	fmt.Println("m2 out ...")
}

// 自定義認證中間件 通過這種方式實現一些靈活的控制
func authMiddleware(doCheck bool)gin.HandlerFunc {
	//連接數據庫
	// 或其他一些準備工作
	return func(c *gin.Context) {
		if doCheck {
			//這裏存放具體的邏輯
			// 是否登錄的判斷
			// if 是登錄用戶
			     c.Next()
			// else
			//   c.Abort()
		}else {
			c.Next()
		}
	}
}

func main()  {
	r := gin.Default()

	// 點開Use 查看源碼發現 Use(middleware ...HandlerFunc) IRoutes
	r.Use(m1, m2, authMiddleware(true))   //全局註冊中間件函數m1 m2 authMiddleware

	/*訪問/index
	 執行indexHandler之前 去執行註冊的中間件  總的執行打印順序是:m1 in  -> m2 in -> index -> m2 out -> m1 out
	*/
	r.GET("/index", indexHandler)
	r.GET("/shop",  func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"msg": "shop",
		})
	})
	r.GET("/user",  func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"msg": "user",
		})
	})

	/* 路由組註冊中間件方法1
	routeGroup1 := r.Group("/xx", authMiddleware(true)){
		routeGroup1.GET("/index", func(c *gin.Context) {
			c.JSON(http.StatusOK, gin.H{"msg": "routeGroup1"})
		})
	}
	路由組註冊中間件方法2
	routeGroup2 := r.Group("/xx2")
	routeGroup2.Use(authMiddleware(true)){
		routeGroup2.GET("/index", func(c *gin.Context) {
			c.JSON(http.StatusOK, gin.H{"msg": "routeGroup2"})
		})
	}
	*/

	r.Run(":9090")
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章