在Gin的整個實現中,中間件可謂是Gin的精髓。一個個中間件組成一條中間件鏈,對HTTP Request請求進行攔截處理,實現了代碼的解耦和分離,並且中間件之間相互不用感知到,每個中間件只需要處理自己需要處理的事情即可。 Gin中常用的中間件是:
Logger 日志
Recovery panic 處理 返回500
BasicAuth 基本認證
Gin默認中間件
在Gin中,我們可以通過Gin提供的默認函數,來構建一個自帶默認中間件的*Engine
。
r := gin.Default()
Default
函數會默認綁定兩個已經准備好的中間件,它們就是Logger 和 Recovery,幫助我們打印日志輸出和painc
處理。
func Default() *Engine { debugPrintWARNINGDefault() engine := New() engine.Use(Logger(), Recovery()) return engine }
從中我們可以看到,Gin的中間件是通過Use
方法設置的,它接收一個可變參數,所以我們同時可以設置多個中間件。
func (engine *Engine) Use(middleware ...HandlerFunc) IRoutes
到了這里其實我們應該更加明白了,一個Gin的中間件,其實就是Gin定義的一個HandlerFunc
,而它在我們Gin中經常使用,比如:
r.GET("/", func(c *gin.Context) { fmt.Println("首頁") c.JSON(200, "") })
后面的func(c *gin.Context)
這部分其實就是一個HandlerFunc
。
在Gin中,為我們提供了gin.BasicAuth
幫我們生成基本認證的中間件,方便我們的開發。
r := gin.Default() r.Use(gin.BasicAuth(gin.Accounts{ "admin": "123456", })) r.GET("/", func(c *gin.Context) { c.JSON(200, "首頁") }) r.Run(":8080")
我們添加一個用戶名為admin
,密碼是123456
的賬戶,用於HTTP 基本認證。現在我們運行啟動,訪問http://localhost:8080/
,這時候只有我們輸入正確的用戶名和密碼,才能看到首頁
,否則是看不到的,這樣我們就達到了授權的目的,就是這么簡單。
針對特定URL的Basic Authorization
其實在實際的項目開發中,我們基本上不太可能對所有的URL都進行認證的,一般只有一些需要認證訪問的數據才需要認證,比如網站的后台,那么這時候我們就可以用分組路由來處理。
func main() { r := gin.Default() r.GET("/", func(c *gin.Context) { c.JSON(200, "首頁") }) adminGroup := r.Group("/admin") adminGroup.Use(gin.BasicAuth(gin.Accounts{ "admin": "123456", })) adminGroup.GET("/index", func(c *gin.Context) { c.JSON(200, "后台首頁") }) r.Run(":8080") }
現在我們運行訪問/
首頁是可以正常顯示的,但是我們訪問/admin/index
會提示輸入密碼,其實所有/admin/*
下的URL都會讓輸入密碼才能訪問,這就是我們分組路由的好處,我們通過把中間件加到/admin
這個分組路由上,就可以達到我們的目的。
通過分組路由的控制,我們可以比較靈活的設置HTTP認證,粒度可以自己隨意控制。
自定義中間件
我們已經知道,Gin的中間件其實就是一個HandlerFunc
,那么只要我們自己實現一個HandlerFunc
,就可以自定義一個自己的中間件。現在我們以統計每次請求的執行時間為例,來演示如何自定義一個中間件。
func costTime() gin.HandlerFunc { return func(c *gin.Context) { //請求前獲取當前時間 nowTime := time.Now() //請求處理 c.Next() //處理后獲取消耗時間 costTime := time.Since(nowTime) url := c.Request.URL.String() fmt.Printf("the request URL %s cost %v\n", url, costTime) } }
以上我們就實現了一個Gin中間件,比較簡單,而且有注釋加以說明,這里要注意的是c.Next
方法,這個是執行后續中間件請求處理的意思(含沒有執行的中間件和我們定義的GET方法處理),這樣我們才能獲取執行的耗時。也就是在c.Next
方法前后分別記錄時間,就可以得出耗時。
有了自定義的中間件,我們就可以這么使用。
func main() { r := gin.New() r.Use(costTime()) r.GET("/", func(c *gin.Context) { c.JSON(200, "首頁") }) r.Run(":8080") }
現在啟動程序,在瀏覽器里打開就可以看到如下日志信息了。
the request URL / cost 26.533µs
通過自定義中間件,我們可以很方便的攔截請求,來做一些我們需要做的事情,比如日志記錄、授權校驗、各種過濾等等。