中間件,英譯middleware,顧名思義,放在中間的物件,那麼放在誰中間呢?原本,客戶端能夠直接請求到服務端接口。git
如今,中間件橫插一腳,它能在請求到達接口以前攔截請求,作一些特殊處理,好比日誌記錄,故障處理等。這就是今天要講述的中間件,那麼,它在Gin框架中是怎麼使用的呢?github
咱們來看一下逢gin
必調的方法Default
,方法中有一個變量engine
,它Use
了Logger
和Recovery
兩個函數,這兩個函數就是gin
框架的日誌和故障處理中間件。golang
func Default() *Engine { debugPrintWARNINGDefault() engine := New() engine.Use(Logger(), Recovery()) return engine }
那就很清楚了,使用中間件就是調用Use
方法就好了唄,問題是如今除了這兩個中間件還能去Use
誰?不如咱先本身寫一箇中間件吧,這樣比較容易理解。shell
寫啥呢,作產品講究MVP,那咱就寫個最簡單的閉環,攔截請求後輸出平也最帥
的日誌,產品就能夠交付了。瀏覽器
寫以前先研究一下官方的Logger
和Recovery
是怎麼寫的,比如葫蘆畫瓢。cookie
func Logger() HandlerFunc { return LoggerWithConfig(LoggerConfig{}) } func Recovery() HandlerFunc { return RecoveryWithWriter(DefaultErrorWriter) }
原來這兩個函數都返回了HandlerFunc
類型,那咱們也模仿寫一個函數就行了。框架
func PingYe() gin.HandlerFunc { return func(c *gin.Context) { c.String(200, "平也最帥") } }
很簡單,寫完了,能夠在main
函數中Use
它了。函數
func main() { r := gin.Default() r.Use(PingYe()) r.Run() }
把項目跑起來,訪問localhsot:8080
看一下,帥呆了,成功渲染數據。編碼
是否是太簡單了?這就交差了?我還能打十個啊!?debug
看來我要把畢生所學都交給你了。
假如咱們定義了兩個中間件,一個是平也最帥,另外一個是在哪裏最帥。
func PingYe() gin.HandlerFunc { return func(c *gin.Context) { c.String(200, "平也最帥") } } func Where() gin.HandlerFunc { return func(c *gin.Context) { c.String(200, "在全宇宙") } }
按順序把它們分別註冊到框架當中,這個時候咱們猜想它會先輸出平也最帥
再輸出在全宇宙
對吧?對,確實是的。
func main() { r := gin.Default() r.Use(PingYe(), Where()) r.Run() }
可是,若是我在不更改註冊順序的前提下,怎麼調換一下順序,先輸出在全宇宙
再輸出平也最帥
呢?這就用到了大名鼎鼎的Next
方法。它的做用就是先執行如下一個中間件,執行完了再回來繼續執行接下來的邏輯。記得是在中間件中調用哦~
func PingYe() gin.HandlerFunc { return func(c *gin.Context) { c.Next() c.String(200, "平也最帥") } }
固然,除了提供Next
方法外,理論上也應該有個中斷操做吧,畢竟拿中間件來作受權驗證的話,驗證失敗後仍是但願阻斷請求的。因此,Abort
就是咱們要找的那個方法。拿上面的例子,在平也最帥
的下一行調用Abort
方法後,Where
中間件就再也不生效了,因而平也只剩下了單純的帥氣。
func PingYe() gin.HandlerFunc { return func(c *gin.Context) { c.String(200, "平也最帥") c.Abort() } }
剛纔我講的中間件是會在全部的路由上生效的,有些不須要添加中間件的路由場景就沒法適應了。因此,咱們須要有能爲局部添加中間件的能力。
咱們先實現給某個接口單獨加中間件,因此先得定義兩個接口know
與unknown
,分別表明認識平也與不認識兩個場景,鑑於認識後才知道平也是全宇宙最帥的,因此要綁中間件,不認識就算了。實現方式很是簡單,往路由後面的參數拼命加中間件就行了。
r.GET("know", PingYe(), Where()) r.GET("unknown", func(c *gin.Context) { c.String(200, "???") })
除了針對某個接口添加中間件外,還能夠針對一組接口添加,一樣調用Use
方法便可。
v1 := r.Group("v1") v1.Use(PingYe(), Where()) { v1.GET("/know", func(c *gin.Context) { c.String(200, "know") }) v1.GET("/unknown", func(c *gin.Context) { c.String(200, "unknown") }) }
基本認證,又稱BasicAuth
,加了基本認證的接口,會讓你在訪問接口時提供用戶名與密碼。
對於瀏覽器用戶,爲了用戶的體驗會自動彈出登陸框,而在其餘場景下是沒有的,那在哪裏輸入帳號密碼呢?實際上,它是經過頭信息傳輸的,頭信息裏有一個固定的格式來表明基本認證。
Authorization: Basic <憑證>
憑證部分是是用戶名和密碼組合的base64
編碼,二者以冒號方式拼接。然鵝,gin
框架的BaseAuth
中間件早已準備好了一切,它能夠短短几行代碼就能解析基本認證的信息。
func main() { r := gin.Default() r.Use(gin.BasicAuth(gin.Accounts{ "pingye": "123", })) r.GET("/secrets", func(c *gin.Context) { user := c.MustGet(gin.AuthUserKey).(string) c.String(200, user+"已登陸成功") }) r.Run() }
示例中的部分代碼可能有些同窗不太明白,好比BasicAuth
方法中的參數,由於基本認證須要帳號和密碼對吧,因此咱們能夠利用gin.Accounts
方便的配置好須要驗證的帳號密碼,gin.Accounts
是一個map類型,鍵表明用戶名,值表明密碼,固然能夠設置不止一個鍵值對,根據你的喜愛自行設置。
代碼中還出現了c.MustGet
方法,這個方法的做用就是必定要取到某個參數,取不到就不幹了panic
,取的是什麼呢?就是gin.AuthUserKey
,在官方中的解釋是基本認證中用戶憑證的cookie
名稱。
// AuthUserKey is the cookie name for user credential in basic auth. const AuthUserKey = "user"
Go語言庫示例開源項目「golang-examples」歡迎star~
https://github.com/pingyeaa/golang-examples
感謝你們的觀看,若是以爲文章對你有所幫助,歡迎關注公衆號「平也」,聚焦Go語言與技術原理。