Gin middleware中间件使用实例

管理员 golangGin middleware中间件使用实例已关闭评论29,548字数 4327阅读14分25秒阅读模式

I've been playing around with Gin web framework in Go for a while for small side projects and its been amazing so far. Gin attracted me by its simplicity and compatibility with a default net/http library and somewhat similarity with Sinatra, which is a minimalistic web framework for Ruby. So far i've written a few open source projects powered by Gin:

While most of those projects are pretty simple under the hood, i started to explore more on how to bring some of my experience with Sinatra into Go. In particular i was interested how to write middleware handlers. You can check Gin's documentation, there's a few small samples.文章源自运维生存时间-https://www.ttlsa.com/golang/gin-middleware-example/

Here's the baseline app:
文章源自运维生存时间-https://www.ttlsa.com/golang/gin-middleware-example/

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

 文章源自运维生存时间-https://www.ttlsa.com/golang/gin-middleware-example/

Now, lets add some middleware:文章源自运维生存时间-https://www.ttlsa.com/golang/gin-middleware-example/

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
}

In example above there's a call c.Next(). It means that after our middleware is done executing we can pass on request handler to the next func in the chain. As you can see, middleware functions are no different from regular endpoint functions as they only take one argument *gin.Context. However, there's also another way of defining middleware functions, like this one:文章源自运维生存时间-https://www.ttlsa.com/golang/gin-middleware-example/

func DummyMiddleware() gin.HandlerFunc {
  // Do some initialization logic here
  // Foo()
  return func(c *gin.Context) {
    c.Next()
  }
}

func main() {
  // ...
  api.Use(DummyMiddleware())
  // ...
}

The difference between those two ways of defining middleware functions is that you can do some initialization logic in later example. Say you need to fetch some data from a third-party service, but you cannot do that on per-request basis. When middleware gets loaded into request chain, whatever you define before the return statement (Foo() in example) will be executed only once. This could be useful if you want to have condition checking, like return one middleware function if one header is present, or another one if its not. Lets move onto examples!文章源自运维生存时间-https://www.ttlsa.com/golang/gin-middleware-example/

Api authentication middleware

If you're building an API with Gin, you will probably want to add some sort of authentication mechanism into your application. Easiest solution is to check if client has provided an additional url parameter, like api_token. Then it should be validated on each request before anything else.文章源自运维生存时间-https://www.ttlsa.com/golang/gin-middleware-example/

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

Example above will check for presence of api_token parameter on every request and validate it against one defined as API_TOKEN environment variable. The important part is if you need to terminate request chain, you can call c.Abort. This will prevent any other handlers from execution.文章源自运维生存时间-https://www.ttlsa.com/golang/gin-middleware-example/

Code revision middleware

This type of middleware usually injects special headers into request response that could provide some idea on which git commit your application is running. In Ruby world that git sha is usually stored in REVISION or COMMIT file in the release directory, created by capistrano or other deployment tools. In fact, i created rack middleware just for that.文章源自运维生存时间-https://www.ttlsa.com/golang/gin-middleware-example/

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

As a result you'll get a new header in http response:文章源自运维生存时间-https://www.ttlsa.com/golang/gin-middleware-example/

X-Revision: d4b371692d361869183d92d84caa5edb8835cf7d

Request ID middleware

Ofter API services inject a special header X-Request-Id to response headers that could be used to track incoming requests for monitoring/debugging purposes. Value of request id header is usually formatted as UUID V4.文章源自运维生存时间-https://www.ttlsa.com/golang/gin-middleware-example/

// ...
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()
  }
}

After you make a request to your service, you'll see a new header in the response, similar to this one:文章源自运维生存时间-https://www.ttlsa.com/golang/gin-middleware-example/

X-Request-Id: ea9ef5f9-107b-4a4e-9295-57d701d85a92
文章源自运维生存时间-https://www.ttlsa.com/golang/gin-middleware-example/文章源自运维生存时间-https://www.ttlsa.com/golang/gin-middleware-example/
weinxin
我的微信
微信公众号
扫一扫关注运维生存时间公众号,获取最新技术文章~
管理员
  • 本文由 发表于 18/01/2018 08:44:41
  • 转载请务必保留本文链接:https://www.ttlsa.com/golang/gin-middleware-example/