gin系列-中間件


Gin框架允許開發者在處理請求的過程中,加入用戶自己的鈎子(Hook)函數。這個鈎子函數就叫中間件,中間件適合處理一些公共的業務邏輯,比如登錄認證、權限校驗、數據分頁、記錄日志、耗時統計等

定義中間件

Gin中的中間件必須是一個gin.HandlerFunc類型

入門案例

package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"net/http"
)

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

//定義一個中間件
func m1(c *gin.Context)  {
	fmt.Println("m1 in ....")
}

func main() {
	r := gin.Default()
	//GET(relativePath string, handlers ...HandlerFunc) IRoutes
	r.GET("/index",m1,indexHandler)
	//r.GET("/index", func(c *gin.Context) {
	//	c.JSON(http.StatusOK, gin.H{
	//		"msg": "indx",
	//	})
	//})
	r.Run(":9090")
}

[GIN-debug] Listening and serving HTTP on :9090
m1 in ....
index in ...
[GIN] 2020/04/21 - 15:21:31 |?[97;42m 200 ?[0m|       998.3µs |       127.0.0.1 |?[97;44m GET     ?[0m "/index"
package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"net/http"
	"time"
)

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

//定義一個中間件:統計耗時
func m1(c *gin.Context)  {
	fmt.Println("m1 in ....")
	//計時
	start := time.Now()
	c.Next() //調用后續的處理函數 執行indexHandler函數
	//c.Abort() //阻止調用后續的處理函數
	cost := time.Since(start)
	fmt.Println("cost:%v\n", cost)
	//輸出
	// m1 in ....
	//index in ...
	//cost:%v
	// 996.8µs
}

func main() {
	r := gin.Default()
	//GET(relativePath string, handlers ...HandlerFunc) IRoutes
	r.GET("/index",m1,indexHandler)  //先執行m1函數再執行indexHandler函數
	//r.GET("/index", func(c *gin.Context) {
	//	c.JSON(http.StatusOK, gin.H{
	//		"msg": "indx",
	//	})
	//})
	r.Run(":9090")
}

注冊中間件

在gin框架中,可以為每個路由添加任意數量的中間件。

為全局路由注冊

package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"net/http"
	"time"
)

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

//定義一個中間件:統計耗時
func m1(c *gin.Context)  {
	fmt.Println("m1 in ....")
	//計時
	start := time.Now()
	c.Next() //調用后續的處理函數 執行indexHandler函數
	//c.Abort() //阻止調用后續的處理函數
	cost := time.Since(start)
	fmt.Println("cost:%v\n", cost)
	fmt.Println("m1 out")
	//輸出
	// [GIN-debug] Listening and serving HTTP on :9090
	//m1 in ....
	//m2 in ....
	//index in ...
	//m2 out
	//cost:%v
	// 997.3µs
	//m1 out
}


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

func main() {
	r := gin.Default()
	r.Use(m1,m2) //全局注冊中間件函數m1,m2    洋蔥模型   類似遞歸調用
	//GET(relativePath string, handlers ...HandlerFunc) IRoutes
	//r.GET("/index",m1,indexHandler)  //先執行m1函數再執行indexHandler函數
	r.GET("/index",indexHandler)
	r.GET("/shop", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"msg": "index",
		})
	})
	r.GET("/user", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"msg": "index",
		})
	})
	r.Run(":9090")
}
package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"net/http"
	"time"
)

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

//定義一個中間件:統計耗時
func m1(c *gin.Context)  {
	fmt.Println("m1 in ....")
	//計時
	start := time.Now()
	c.Next() //調用后續的處理函數 執行indexHandler函數
	//c.Abort() //阻止調用后續的處理函數
	cost := time.Since(start)
	fmt.Println("cost:%v\n", cost)
	fmt.Println("m1 out")
	//輸出
	// [GIN-debug] Listening and serving HTTP on :9090
	//m1 in ....
	//m2 in ....
	//m2 out
	//cost:%v
	// 997.8µs
	//m1 out
}


func m2(c *gin.Context)  {
	fmt.Println("m2 in ....")
	//c.Next() //調用后續的處理函數
	c.Abort() //阻止后續調用
	//return   //return 立即結束m2函數 
	//m1 in ....
	//m2 in ....
	//cost:%v
	// 0s
	//m1 out

	fmt.Println("m2 out")
}

//func authMiddleware(c *gin.Context)  {   //通常寫成閉包
//	//是否登陸的判斷
//	//if 是登陸用戶
//	//c.Next()
//	//else
//	//c.Abort()
//}

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()
	r.Use(m1,m2,authMiddleware(true)) //全局注冊中間件函數m1,m2    洋蔥模型   類似遞歸調用
	//GET(relativePath string, handlers ...HandlerFunc) IRoutes
	//r.GET("/index",m1,indexHandler)  //先執行m1函數再執行indexHandler函數
	r.GET("/index",indexHandler)
	r.GET("/shop", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"msg": "index",
		})
	})
	r.GET("/user", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"msg": "index",
		})
	})
	r.Run(":9090")
}

為某個路由單獨注冊

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"net/http"
	"time"
)

//定義一個中間件:統計耗時
func m1(c *gin.Context)  {
	fmt.Println("m1 in ....")
	//計時
	start := time.Now()
	c.Next() //調用后續的處理函數 執行indexHandler函數
	//c.Abort() //阻止調用后續的處理函數
	cost := time.Since(start)
	fmt.Println("cost:%v\n", cost)
	fmt.Println("m1 out")
}

func main() {
	r := gin.Default()
	r.GET("/user", m1, func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"msg": "index",
		})
	})
	//m1 in ....
	//cost:%v
	// 0s
	//m1 out
	r.Run(":9090")
}
import (
	"fmt"
	"github.com/gin-gonic/gin"
	"net/http"
	"time"
)

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

//定義一個中間件:統計耗時
func m1(c *gin.Context)  {
	fmt.Println("m1 in ....")
	//計時
	start := time.Now()
	c.Next() //調用后續的處理函數 執行indexHandler函數
	//c.Abort() //阻止調用后續的處理函數
	cost := time.Since(start)
	fmt.Println("cost:%v\n", cost)
	fmt.Println("m1 out")
}


func m2(c *gin.Context)  {
	fmt.Println("m2 in ....")
	//c.Next() //調用后續的處理函數
	c.Abort() //阻止后續調用
	//return   //return 立即結束m2函數
	//m1 in ....
	//m2 in ....
	//cost:%v
	// 0s
	//m1 out

	fmt.Println("m2 out")
}

func main() {
	r := gin.Default()
	r.GET("/user", m1,m2, func(c *gin.Context) {  //可以單獨多個路由
		c.JSON(http.StatusOK, gin.H{
			"msg": "index",
		})
	})
	//[GIN-debug] Listening and serving HTTP on :9090
	//m1 in ....
	//m2 in ....
	//m2 out
	//cost:%v
	// 0s
	//m1 out
	r.Run(":9090")
}

為路由組注冊中間件

func main() {
	//路由組注冊中間件方法1:
	xxGroup := r.Group("/xx", authMiddleware(true))
	{
		xxGroup.GET("/index", func(c *gin.Context) {
			c.JSON(http.StatusOK, gin.H{"msg":"xxGroup"})
		})
	}
	//路由組注冊中間件方法2:
	xx2Group := r.Group("/xx")
	xx2Group.Use(authMiddleware(true))
	{
		xxGroup.GET("/index", func(c *gin.Context) {
			c.JSON(http.StatusOK, gin.H{"msg":"xxGroup"})
		})
	}
	r.Run(":9090")
}

跨中間件存取值

package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"net/http"
	"time"
)

func indexHandler(c *gin.Context) {
	fmt.Println("index in ...")
	name, ok := c.Get("name")   //從上下文中取值,跨中間件存取值
	if !ok {
		name = "匿名用戶"
	}
	c.JSON(http.StatusOK, gin.H{
		"msg": name,
	})
}

//定義一個中間件:統計耗時
func m1(c *gin.Context)  {
	fmt.Println("m1 in ....")
	//計時
	start := time.Now()
	c.Next() //調用后續的處理函數 執行indexHandler函數
	//c.Abort() //阻止調用后續的處理函數
	cost := time.Since(start)
	fmt.Println("cost:%v\n", cost)
	fmt.Println("m1 out")
}


func m2(c *gin.Context)  {
	fmt.Println("m2 in ....")
	c.Set("name","zisefeizhu")  //在上下文中設置c的值
	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()
	r.Use(m1,m2,authMiddleware(true)) //全局注冊中間件函數m1,m2    洋蔥模型   類似遞歸調用
	//GET(relativePath string, handlers ...HandlerFunc) IRoutes
	//r.GET("/index",m1,indexHandler)  //先執行m1函數再執行indexHandler函數
	r.GET("/index",indexHandler)
	r.Run(":9090")
}

中間件注意事項

gin.Default()

gin.Default()默認使用了Logger和Recovery中間件,其中:Logger中間件將日志寫入gin.DefaultWriter,即使配置了GIN_MODE=release。Recovery中間件會recover任何panic。如果有panic的話,會寫入500響應碼。如果不想使用上面兩個默認的中間件,可以使用gin.New()新建一個沒有任何默認中間件的路由。

package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"net/http"
	"time"
)

func indexHandler(c *gin.Context) {
	fmt.Println("index in ...")
	name, ok := c.Get("name")   //從上下文中取值,跨中間件存取值
	if !ok {
		name = "匿名用戶"
	}
	c.JSON(http.StatusOK, gin.H{
		"msg": name,
	})
}

//定義一個中間件:統計耗時
func m1(c *gin.Context)  {
	fmt.Println("m1 in ....")
	//計時
	start := time.Now()
	c.Next() //調用后續的處理函數 執行indexHandler函數
	//c.Abort() //阻止調用后續的處理函數
	cost := time.Since(start)
	fmt.Println("cost:%v\n", cost)
	fmt.Println("m1 out")
}


func m2(c *gin.Context)  {
	fmt.Println("m2 in ....")
	c.Set("name","zisefeizhu")  //在上下文中設置c的值
	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()  //默認使用Logger()和Recovery()中間件
	r := gin.New()
	r.Use(m1,m2,authMiddleware(true)) //全局注冊中間件函數m1,m2    洋蔥模型   類似遞歸調用
	r.GET("/index",indexHandler)
	r.GET("/shop", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"msg": "index",
		})
	})
	r.GET("/user", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"msg": "index",
		})
	})
	r.Run(":9090")
}

[GIN-debug] Listening and serving HTTP on :9090
m1 in ....
m2 in ....
m2 out
index in ...
cost:%v
 1.0137ms
m1 out

gin中間件中使用goroutine

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

//定義一個中間件:統計耗時
func m1(c *gin.Context)  {
	fmt.Println("m1 in ....")
	//計時
	start := time.Now()
	go funcXX(c.Copy()) //在funcXX中只能使用c的拷貝
	c.Next() //調用后續的處理函數 執行indexHandler函數
	//c.Abort() //阻止調用后續的處理函數
	cost := time.Since(start)
	fmt.Println("cost:%v\n", cost)
	fmt.Println("m1 out")
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM