Gin middleware中間件使用實例

Gin middleware中間件使用實例

2018.04.07 11:43 字數 945 閱讀 4388評論 0喜歡 6

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

翻譯:devabel

我最近一段時間一直使用Go的Gin web框架開發一些小型項目,迄今爲止它的表現一直很棒。Gin因其簡單性和與默認net/http庫的兼容性而吸引了我,並且與Sinatra相似, Sinatra是一種簡約的Ruby Ruby框架。到目前爲止,我已經寫了幾個由Gin驅動的開源項目:

pgweb - PostgreSQL的WEB界面
omxremote - 用於Raspberry Pi omxplayer的GUI和API
envd - 通過HTTP爲環境變量提供服務的API
hipache-API - HTTP API的Hipache

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

這是基準應用程序:


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")

}

現在,讓我們添加一些中間件


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

}

在上面的例子中調用了c.Next(),這意味着在我們的中間件完成執行後,我們可以將請求處理程序傳遞給鏈中的下一個func。正如你看到的,中間件功能與常規端點功能沒有區別,因爲它們只有一個參數gin.Context。但是,還有另一種定義中間件*功能的方式,就像這樣:

func DummyMiddleware() gin.HandlerFunc {

  // Do some initialization logic here

  // Foo()

  return func(c *gin.Context) {

    c.Next()

  }

}

func main() {

  // ...

  api.Use(DummyMiddleware())

  // ...

}

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

Api認證中間件

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

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每個請求中是否存在參數,並根據定義爲API_TOKEN環境變量的值對其進行驗證。重要的部分是如果你需要終止請求鏈,你可以調用c.Abort。這將防止任何其他處理程序執行。

代碼修改中間件

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

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()

  }

}

結果你會在http響應中得到一個新的標題:

X-Revision: d4b371692d361869183d92d84caa5edb8835cf7d

請求ID 中間件

在API服務之後,X-Request-Id爲響應頭部注入一個特殊的頭部,可用於跟蹤傳入的請求以進行監視/調試。請求標頭的值通常被格式化爲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()
  }
}

在向服務端發出請求後,您會在響應中看到一個新的頭信息,與此類似:

X-Request-Id: ea9ef5f9-107b-4a4e-9295-57d701d85a92
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章