debugPrintWARNINGDefault()
engine := New()
engine.Use(Logger(), Recovery())
return engine
}

它先使用New()方法初始化一個引擎,然后再調用引擎的Use 方法,加載了兩個「中間件」

func (engine *Engine) Use(middleware ...HandlerFunc) IRoutes {
engine.RouterGroup.Use(middleware...)
engine.rebuild404Handlers()
engine.rebuild405Handlers()
return engine
}

加載了兩個gin中的中間件,Logger()與Recovery()

Logger()的源碼為

func Logger() HandlerFunc {
return LoggerWithConfig(LoggerConfig{})
}

Recovery() 的源碼為

func Recovery() HandlerFunc {
return RecoveryWithWriter(DefaultErrorWriter)
}

什么是中間件

中間件為一類函數,「HandlerFunc」 , 定義為 type HandlerFunc func(*Context)

也就是該函數的參數為Context,也就是說,如果我們要自定義一個中間件函數的話,只需要返回一個參數為(*gin.Content)的函數即可。

何為中間件?當一個請求到達gin服務的某個路由以后,gin 會根據路由中定義好的處理類來進行處理,以GET方法為例

func (group *RouterGroup) GET(relativePath string, handlers ...HandlerFunc) IRoutes {
return group.handle(http.MethodGet, relativePath, handlers)
}

handlers 為不定參數,也就是說可以有多個處理類,而這里的處理類類型也是HandlerFunc,和中間件是一樣的。

可以理解為是中間件為多個處理請求的Handler,某個請求先經過一個Handler, 之后再經過第二個,第三個,最后將結果返回給調用者。

中間件函數中有以下兩個方法比較重要

Next() 方法,該中間件處理以后,交由下一個中間件處理

Abort() 方法,調用完該方法以后,之后的HandlerFunc則不進行處理了

中間件的兩種定義方式

中間件常用的有兩種方式

  1. 定義一個返回值為gin.HandlerFunc?的函數,
  2. 直接定義一個參數為*gin.Context?的函數
package midwares

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

//打印耗時的中間件

func Checktime() gin.HandlerFunc {
//這里可以處理一些別的邏輯
return func(c *gin.Context) {
start := time.Now()
c.Next()
spend:= time.Since(start).Microseconds()
fmt.Printf("use: %d \n", spend)
}
}

func Abort(c *gin.Context){
fmt.Println("使用了Abort中間件,不會進行之后處理")
c.JSON(200, gin.H{"msg": "no next"})
c.Abort()
}

這兩種方式效果是一樣的,只是在gin初始化加載的方式不同

r := gin.Default()
r.Use(midwares.Checktime()) //需要加上()
r.Use(midwares.Abort) // 不需要加上()

個人還是比較喜歡加上()的方式。

中間件的幾種使用方式

中間件有兩種使用方式,一種是全局的中間件,一種是局部中間件

如上面的使用r.Use(midware) 的方式是全局的,這種方式,每個路由都會走該中間件的邏輯。

局部中間件為在路由定義時使用,這種定義則只在該路由上有效.

userv1.GET("/abort", midwares.Abort, userv1_h.Abort)

上面我定義了兩個中間件,Checktime 為記錄下該請求所用的時間,Abort 中間件為測試c.Abort 函數功能,使用了該中間件的路由只會走到這里,不會再經過之后的路由了。

訪問上面的路由地址?/abort?以下,控制臺會輸出

使用了Abort中間件,不會進行之后處理
use: 443

第一行輸出為「Abort」 中間件的輸出,第二行輸出為「Checktime」中間件的輸出。

http的返回為Abort中間件定義的返回,之后的HandlerFunc不再執行了。

{
msg: "no next"
}

基于中間件的授權管理

創建一個中間件,如果校驗成功則繼續往下走,如果不是管理員,則就不要往下走了,返回401

func CheckAdmin() gin.HandlerFunc{
return func(c *gin.Context) {
username := c.Query("user")
// 這里可以是從cookie或者 session 中判斷
if username == "admin"{
c.Next()
}else{
c.JSON(401, gin.H{"msg": "No Private"})
c.Abort()
}
}
}

中間件的執行順序

gin在初始化的時候加載了一些中間件,又定義了全局的中間件,又定義了路由的中間件,那么這些中間件的執行順序是如何的呢?

執行的順序為 全局中間件 > 路由組中間件 > 路由中間件。

參考文章

Gin框架入門(四)—中間件[1]

本文章轉載微信公眾號@序語程言

上一篇:

使用gin搭建api后臺系統之cookie與session

下一篇:

結合gin+gorm+go-Redis寫一個基礎 API
#你可能也喜歡這些API文章!

我們有何不同?

API服務商零注冊

多API并行試用

數據驅動選型,提升決策效率

查看全部API→
??

熱門場景實測,選對API

#AI文本生成大模型API

對比大模型API的內容創意新穎性、情感共鳴力、商業轉化潛力

25個渠道
一鍵對比試用API 限時免費

#AI深度推理大模型API

對比大模型API的邏輯推理準確性、分析深度、可視化建議合理性

10個渠道
一鍵對比試用API 限時免費