Go Web輕量級框架Gin學習系列:中間件使用詳解

原創做者,公衆號【程序員讀書】,歡迎關注公衆號,轉載文章請註明出處哦。程序員

在今天這篇文章中,咱們來談談Gin框架中間件(middleware)的使用,應該說Gin的中間件是Gin框架中一個很是重要的內容,並且Gin中間件也是使用Gin框架開發一個完整Web程序時不可或缺的部分,因此有必要好了解一下。json

什麼是Gin中間件

Gin中間件是什麼?Gin中間件的做用是什麼?要怎麼樣使用中間件呢?bash

1. Gin中間件的做用

好吧,簡單來講,Gin中間件的做用有兩個:框架

  1. Web請求到到達咱們定義的HTTP請求處理方法以前,攔截請求並進行相應處理(好比:權限驗證,數據過濾等),這個能夠類比爲前置攔截器前置過濾器函數

  2. 在咱們處理完成請求並響應客戶端時,攔截響應並進行相應的處理(好比:添加統一響應部頭或數據格式等),這能夠類型爲後置攔截器後置過濾器學習

2. Gin中間件的定義

在Gin框架中,中間件的類型定義以下代碼所示,能夠看出,中間件實際上就是一個以gin.Context爲形參的函數而已,與咱們定義處理HTTP請求的Handler本質上是同樣的,並無什麼神祕可言。ui

type HandlerFunc func(*Context)
複製代碼

3. Gin內置中間件

在使用Gin框架開發Web應用時,經常須要自定義中間件,不過,Gin也內置一些中間件,咱們能夠直接使用,下面是內置中間件列表:spa

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時,已經默認使用了RecoveryLogger中間件,從下面gin.Default()方法的源碼能夠看出:debug

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.ContextNext()方法,則能夠請求到達並完成業務處理後,再通過中間件後置攔截處理,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應用時,中間件是必用的知識。


你的關注,是我寫做路上最大的鼓勵!

相關文章
相關標籤/搜索