在今天這篇文章中,我們來談談Gin框架中介軟體(middleware
)的使用,應該說Gin的中介軟體是Gin框架中一個非常重要的內容,而且Gin中介軟體也是使用Gin框架開發一個完整Web程式時不可或缺的部分,所以有必要好了解一下。
什麼是Gin中介軟體
Gin中介軟體是什麼?Gin中介軟體的作用是什麼?要怎麼樣使用中介軟體呢?
1. Gin中介軟體的作用
好吧,簡單來說,Gin中介軟體的作用有兩個:
-
Web請求到到達我們定義的HTTP請求處理方法之前,攔截請求並進行相應處理(比如:許可權驗證,資料過濾等),這個可以類比為
前置攔截器
或前置過濾器
, -
在我們處理完成請求並響應客戶端時,攔截響應並進行相應的處理(比如:新增統一響應部頭或資料格式等),這可以型別為
後置攔截器
或後置過濾器
。
2. Gin中介軟體的定義
在Gin框架中,中介軟體的型別定義如下程式碼所示,可以看出,中介軟體實際上就是一個以gin.Context為形參的函式而已,與我們定義處理HTTP請求的Handler本質上是一樣的,並沒有什麼神祕可言。
type HandlerFunc func(*Context)
複製程式碼
3. Gin內建中介軟體
在使用Gin框架開發Web應用時,常常需要自定義中介軟體,不過,Gin也內建一些中介軟體,我們可以直接使用,下面是內建中介軟體列表:
func BasicAuth(accounts Accounts) HandlerFunc
func BasicAuthForRealm(accounts Accounts, realm string) HandlerFunc
func Bind(val interface{}) HandlerFunc //攔截請求引數並進行繫結
func ErrorLogger() HandlerFunc //錯誤日誌處理
func ErrorLoggerT(typ ErrorType) HandlerFunc //自定義型別的錯誤日誌處理
func Logger() HandlerFunc //日誌記錄
func LoggerWithConfig(conf LoggerConfig) HandlerFunc
func LoggerWithFormatter(f LogFormatter) HandlerFunc
func LoggerWithWriter(out io.Writer, notlogged ...string) HandlerFunc
func Recovery() HandlerFunc
func RecoveryWithWriter(out io.Writer) HandlerFunc
func WrapF(f http.HandlerFunc) HandlerFunc //將http.HandlerFunc包裝成中介軟體
func WrapH(h http.Handler) HandlerFunc //將http.Handler包裝成中介軟體
複製程式碼
中間的使用
1. 不使用預設中介軟體
使用gin.Default()
返回的gin.Engine
時,已經預設使用了Recovery
和Logger
中介軟體,從下面gin.Default()
方法的原始碼可以看出:
func Default() *Engine {
debugPrintWARNINGDefault()
engine := New()
engine.Use(Logger(), Recovery())//使用Recovery和Logger中間
return engine
}
複製程式碼
當我們不想使用這兩個中介軟體時,可以使用gin.New()方法返回一個不帶中介軟體的gin.Engine物件:
router := gin.New()//不帶中介軟體
複製程式碼
2. 全域性使用中介軟體
直拉使用gin.Engine
結構體的Use()
方法便可以在所有請求應用中介軟體,這樣做,中介軟體便會在全域性起作用。
router := gin.New()
router.Use(gin.Recovery())//在全域性使用內建中介軟體
複製程式碼
3. 路由分組使用中介軟體
更多的時候,我們會根據業務不同劃分不同路由分組(RouterGroup )
,不同的路由分組再應用不同的中介軟體,這樣就達到了不同的請求由不同的中介軟體進行攔截處理。
router := gin.New()
user := router.Group("user", gin.Logger(),gin.Recovery())
{
user.GET("info", func(context *gin.Context) {
})
user.GET("article", func(context *gin.Context) {
})
}
複製程式碼
4. 單個路由使用中介軟體
除了路由分組,單個請求路由,也可以應用中介軟體,如下:
router := gin.New()
router.GET("/test",gin.Recovery(),func(c *gin.Context){
c.JSON(200,"test")
})
複製程式碼
也可以在單個路由中使用多箇中介軟體,如下:
router := gin.New()
router.GET("/test",gin.Recovery(),gin.Logger(),func(c *gin.Context){
c.JSON(200,"test")
})
複製程式碼
自定義中介軟體
上面的講解中,我們看到,雖然Gin提供了一些中介軟體,我們直接使用即可,但內建中介軟體可能滿足不我們業務開發的需求,在開發過程中我們需要開自己的中介軟體,這在Gin框架中是非常簡單的一件事。
在前面,我們看到Gin框架自帶的中介軟體方法,都是返回HandlerFunc
型別,其定義如下:
type HandlerFunc func(*Context)
複製程式碼
HandlerFunc規範了Gin中介軟體的定義,所以自定義中介軟體,如下:
//定義中介軟體
func MyMiddleware(c *gin.Context){
//中介軟體邏輯
}
複製程式碼
定義好中介軟體,便可使用中介軟體,這裡演示的是全域性使用,也可以在單個路由或路由分組中使用:
router = gin.Default()
router.Use(MyMiddleware)
複製程式碼
或者,通過自定義方法,返回一箇中介軟體函式,這是Gin框架中更常用的方式:
//定義一個返回中介軟體的方法
func MyMiddleware(){
//自定義邏輯
//返回中介軟體
return func(c *gin.Context){
//中介軟體邏輯
}
}
複製程式碼
使用自定義的中介軟體,注意MyMiddleware方法後面有加括號:
router = gin.Default()
router.Use(MyMiddleware())
複製程式碼
資料傳遞
當我們在中介軟體攔截並預先處理好資料之後,要如何將資料傳遞我們定義的處理請求的HTTP方法呢?可以使用gin.Context
中的Set()
方法,其定義如下,Set()
通過一個key來儲存作何型別的資料,方便下一層處理方法獲取。
func (c *Context) Set(key string, value interface{})
複製程式碼
當我們在中介軟體中通過Set方法設定一些數值,在下一層中介軟體或HTTP請求處理方法中,可以使用下面列出的方法通過key獲取對應資料。
其中,gin.Context的Get方法返回interface{}
,通過返回exists可以判斷key是否存在。
func (c *Context) Get(key string) (value interface{}, exists bool)
複製程式碼
當我們確定通過Set方法設定對應資料型別的值時,可以使用下面方法獲取應資料型別的值。
func (c *Context) GetBool(key string) (b bool)
func (c *Context) GetDuration(key string) (d time.Duration)
func (c *Context) GetFloat64(key string) (f64 float64)
func (c *Context) GetInt(key string) (i int)
func (c *Context) GetInt64(key string) (i64 int64)
func (c *Context) GetString(key string) (s string)
func (c *Context) GetStringMap(key string) (sm map[string]interface{})
func (c *Context) GetStringMapString(key string) (sms map[string]string)
func (c *Context) GetStringMapStringSlice(key string) (smss map[string][]string)
func (c *Context) GetStringSlice(key string) (ss []string)
func (c *Context) GetTime(key string) (t time.Time)
複製程式碼
示例程式碼:
//自定義中介軟體
func MyMiddleware(c *gin.Context){
c.Set("mykey",10)
}
router := gin.New()
router.GET("test",MyMiddleware,func(c *gin.Context){
c.GetInt("mykey")//我們知道設定進行的是整型,所以使用GetInt方法來獲取
})
複製程式碼
攔截請求與後置攔截
1. 攔截請求
我們說過,中介軟體的最大作用就是攔截過濾請求,比如我們有些請求需要使用者登入或者需要特定許可權才能訪問,這時候便可以中介軟體中做過濾攔截,當使用者請求不合法時,可以使用下面列出的gin.Context
的幾個方法中斷使用者請求:
下面三個方法中斷請求後,直接返回200,但響應的body中不會有資料。
func (c *Context) Abort()
func (c *Context) AbortWithError(code int, err error) *Error
func (c *Context) AbortWithStatus(code int)
複製程式碼
使用AbortWithStatusJSON()方法,中斷使用者請求後,則可以返回json格式的資料.
func (c *Context) AbortWithStatusJSON(code int, jsonObj interface{})
複製程式碼
2. 後置攔截
前面我們講的都是到達我們定義的HTTP處理方法前進行攔截,其實,如果在中介軟體中呼叫gin.Context
的Next()
方法,則可以請求到達並完成業務處理後,再經過中介軟體後置攔截處理,Next()
方法定義如下:。
func (c *Context) Next()
複製程式碼
在中介軟體呼叫Next()
方法,Next()
方法之前的程式碼會在到達請求方法前執行,Next()
方法之後的程式碼則在請求方法處理後執行:
func MyMiddleware(c *gin.Context){
//請求前
c.Next()
//請求後
}
複製程式碼
示例程式碼
func MyMiddleware(c *gin.Context){
c.Set("key",1000)//請求前
c.Next()
c.JSON(http.StatusOK,c.GetInt("key"))//請求後
}
router := gin.New()
router.GET("test", MyMiddleware, func(c *gin.Context) {
k := c.GetInt("key")
c.Set("key", k+2000)
})
router.Run()
複製程式碼
上面示例程式執行結果為3000,通過上面這樣一個簡單的示例程式,我們可以看到中介軟體在請求攔截請求,處理資料並控制Web請求流程的作用。
小結
學習Gin框架,中介軟體middleware
非常重要的一塊知識,它可以我們定義處理HTTP請求的方法前攔截不合法的HTTP請求,或者預先處理好資料,或響應時新增統一的響應頭部,因此在使用Gin開發Web應用時,中介軟體是必用的知識。