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