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")
}