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

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

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

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

Logger()的源碼為

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

Recovery() 的源碼為

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

什么是中間件

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

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

何為中間件?當(dāng)一個(gè)請(qǐng)求到達(dá)gin服務(wù)的某個(gè)路由以后,gin 會(huì)根據(jù)路由中定義好的處理類來進(jìn)行處理,以GET方法為例

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

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

可以理解為是中間件為多個(gè)處理請(qǐng)求的Handler,某個(gè)請(qǐng)求先經(jīng)過一個(gè)Handler, 之后再經(jīng)過第二個(gè),第三個(gè),最后將結(jié)果返回給調(diào)用者。

中間件函數(shù)中有以下兩個(gè)方法比較重要

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

Abort() 方法,調(diào)用完該方法以后,之后的HandlerFunc則不進(jìn)行處理了

中間件的兩種定義方式

中間件常用的有兩種方式

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

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

//打印耗時(shí)的中間件

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中間件,不會(huì)進(jìn)行之后處理")
c.JSON(200, gin.H{"msg": "no next"})
c.Abort()
}

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

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

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

中間件的幾種使用方式

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

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

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

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

上面我定義了兩個(gè)中間件,Checktime 為記錄下該請(qǐng)求所用的時(shí)間,Abort 中間件為測試c.Abort 函數(shù)功能,使用了該中間件的路由只會(huì)走到這里,不會(huì)再經(jīng)過之后的路由了。

訪問上面的路由地址?/abort?以下,控制臺(tái)會(huì)輸出

使用了Abort中間件,不會(huì)進(jìn)行之后處理
use: 443

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

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

{
msg: "no next"
}

基于中間件的授權(quán)管理

創(chuàng)建一個(gè)中間件,如果校驗(yàn)成功則繼續(xù)往下走,如果不是管理員,則就不要往下走了,返回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()
}
}
}

中間件的執(zhí)行順序

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

執(zhí)行的順序?yàn)?全局中間件 > 路由組中間件 > 路由中間件。

參考文章

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

本文章轉(zhuǎn)載微信公眾號(hào)@序語程言

上一篇:

使用gin搭建api后臺(tái)系統(tǒng)之cookie與session

下一篇:

結(jié)合gin+gorm+go-Redis寫一個(gè)基礎(chǔ) API
#你可能也喜歡這些API文章!

我們有何不同?

API服務(wù)商零注冊(cè)

多API并行試用

數(shù)據(jù)驅(qū)動(dòng)選型,提升決策效率

查看全部API→
??

熱門場景實(shí)測,選對(duì)API

#AI文本生成大模型API

對(duì)比大模型API的內(nèi)容創(chuàng)意新穎性、情感共鳴力、商業(yè)轉(zhuǎn)化潛力

25個(gè)渠道
一鍵對(duì)比試用API 限時(shí)免費(fèi)

#AI深度推理大模型API

對(duì)比大模型API的邏輯推理準(zhǔn)確性、分析深度、可視化建議合理性

10個(gè)渠道
一鍵對(duì)比試用API 限時(shí)免費(fèi)