Gin middleware中間件使用實(shí)例

原文:http://www.ttlsa.com/golang/gin-middleware-example/

翻譯:devabel

我最近一段時(shí)間一直使用Go的Gin web框架開發(fā)一些小型項(xiàng)目,迄今為止它的表現(xiàn)一直很棒。Gin因其簡單性和與默認(rèn)net/http庫的兼容性而吸引了我,并且與Sinatra相似, Sinatra是一種簡約的Ruby Ruby框架。到目前為止,我已經(jīng)寫了幾個(gè)由Gin驅(qū)動的開源項(xiàng)目:

pgweb - PostgreSQL的WEB界面
omxremote - 用于Raspberry Pi omxplayer的GUI和API
envd - 通過HTTP為環(huán)境變量提供服務(wù)的API
hipache-API - HTTP API的Hipache

盡管這些項(xiàng)目中的大多數(shù)都非常簡單,但我開始更多地探索如何將我的一些使用Sinatra經(jīng)驗(yàn)帶入Go。我特別感興趣的是如何編寫中間件處理程序。你可以查看Gin的文檔,有幾個(gè)小例子。

這是基準(zhǔn)應(yīng)用程序:


package main

import(

  "github.com/gin-gonic/gin"

)

func GetDummyEndpoint(c *gin.Context) {

  resp := map[string]string{"hello":"world"}

  c.JSON(200, resp)

}

func main() {

  api := gin.Default()

  api.GET("/dummy", GetDummyEndpoint)

  api.Run(":5000")

}

現(xiàn)在,讓我們添加一些中間件


func DummyMiddleware(c *gin.Context) {

  fmt.Println("Im a dummy!")

  // Pass on to the next-in-chain

  c.Next()

}

func main() {

  // Insert this middleware definition before any routes

  api.Use(DummyMiddleware)

  // ... more code

}

在上面的例子中調(diào)用了c.Next(),這意味著在我們的中間件完成執(zhí)行后,我們可以將請求處理程序傳遞給鏈中的下一個(gè)func。正如你看到的,中間件功能與常規(guī)端點(diǎn)功能沒有區(qū)別,因?yàn)樗鼈冎挥幸粋€(gè)參數(shù)gin.Context。但是,還有另一種定義中間件*功能的方式,就像這樣:

func DummyMiddleware() gin.HandlerFunc {

  // Do some initialization logic here

  // Foo()

  return func(c *gin.Context) {

    c.Next()

  }

}

func main() {

  // ...

  api.Use(DummyMiddleware())

  // ...

}

這兩種定義中間件功能的方式之間的區(qū)別在于,您可以在稍后的示例中執(zhí)行一些初始化邏輯。假設(shè)你需要從第三方服務(wù)中獲取一些數(shù)據(jù),但是你不能在每個(gè)請求的基礎(chǔ)上這樣做。當(dāng)中間件 被加載到請求鏈中時(shí),無論您在return語句之前定義的內(nèi)容(Foo()例如)將只執(zhí)行一次。如果您想要進(jìn)行條件檢查,比如返回一個(gè)中間件函數(shù)(如果存在一個(gè)頭)或者另一個(gè)中間件函數(shù)(如果不存在),這可能很有用。讓我們來看看例子!

Api認(rèn)證中間件

如果你正在用杜松子建立一個(gè)API ,你可能會想在你的應(yīng)用程序中添加一些認(rèn)證機(jī)制。最簡單的解決方案是檢查客戶端是否提供了額外的url參數(shù),如api_token。然后,應(yīng)該在每個(gè)請求之前對其進(jìn)行驗(yàn)證。

func respondWithError(code, message, *gin.Context) {

  resp := map[string]string{"error": message}

  c.JSON(code, resp)

  c.Abort(code)

}

func TokenAuthMiddleware() gin.HandlerFunc {

  return func(c *gin.Context) {

    token := c.Request.FormValue("api_token")

    if token == "" {

      respondWithError(401, "API token required", c)

      return

    }

    if token != os.Getenv("API_TOKEN") {

      respondWithError(401, "Invalid API token", c)

      return

    }

    c.Next()

  }

}

上面的例子將檢查api_token每個(gè)請求中是否存在參數(shù),并根據(jù)定義為API_TOKEN環(huán)境變量的值對其進(jìn)行驗(yàn)證。重要的部分是如果你需要終止請求鏈,你可以調(diào)用c.Abort。這將防止任何其他處理程序執(zhí)行。

代碼修改中間件

這種類型的中間件通常會在請求響應(yīng)中插入特殊的頭文件,以提供有關(guān)運(yùn)行應(yīng)用程序的git提交的一些信息。在Ruby世界中,git sha通常存儲在由capistrano或其他部署工具創(chuàng)建的版本目錄中REVISION或存儲在COMMIT文件中。事實(shí)上,我為此創(chuàng)建了機(jī)架中間件

func RevisionMiddleware() gin.HandlerFunc {

  // Revision file contents will be only loaded once per process

  data, err := ioutil.ReadFile("REVISION")

  // If we cant read file, just skip to the next request handler

  // This is pretty much a NOOP middlware :)

  if err != nil {

    return func(c *gin.Context) {

      c.Next()

    }

  }

  // Clean up the value since it could contain line breaks

  revision := strings.TrimSpace(string(data))

  // Set out header value for each response

  return func(c *gin.Context) {

    c.Writer.Header().Set("X-Revision", revision)

    c.Next()

  }

}

結(jié)果你會在http響應(yīng)中得到一個(gè)新的標(biāo)題:

X-Revision: d4b371692d361869183d92d84caa5edb8835cf7d

請求ID 中間件

在API服務(wù)之后,X-Request-Id為響應(yīng)頭部注入一個(gè)特殊的頭部,可用于跟蹤傳入的請求以進(jìn)行監(jiān)視/調(diào)試。請求標(biāo)頭的值通常被格式化為UUID V4

// ...
import github.com/satori/go.uuid
// ...

func RequestIdMiddleware() gin.HandlerFunc {
  return func(c *gin.Context) {
    c.Writer.Header().Set("X-Request-Id", uuid.NewV4().String())
    c.Next()
  }
}

在向服務(wù)端發(fā)出請求后,您會在響應(yīng)中看到一個(gè)新的頭信息,與此類似:

X-Request-Id: ea9ef5f9-107b-4a4e-9295-57d701d85a92
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,868評論 18 139
  • 使用Gin構(gòu)建Go Web應(yīng)用程序和微服務(wù) 原文鏈接:https://semaphoreci.com/commun...
    devabel閱讀 15,906評論 2 28
  • 5年前的一天,我的女兒呱呱墜地,那時(shí)的我就在想“我該怎樣教育她”,“我該當(dāng)虎媽還是貓媽”,想來想去,隨著她漸漸的長...
    daisy常閱讀 250評論 0 2
  • 今天吃完晚飯,特意跑到博學(xué)廳,觀看學(xué)校的歌手組合大賽。這種“帥哥與美女云集,視覺與聽覺的盛宴”,再吸睛不過了! 暫...
    涂涂笨加菲閱讀 445評論 0 2
  • 在戀愛時(shí)人總覺得對方是天使,而在相處時(shí)卻認(rèn)為對方是魔鬼。 其實(shí)每個(gè)人都是復(fù)雜的存在吧,缺乏理智的時(shí)候,總是顯得那么...
    縈紓閱讀 210評論 0 1