【问题标题】:How to log response body in gin如何在杜松子酒中记录响应正文
【发布时间】:2016-11-24 20:59:25
【问题描述】:

我需要在 gin 的中间件中记录响应正文,但我不知道如何获取响应正文。有人可以帮忙吗?

我正在使用这样的中间件:

func Logger() gin.HandlerFunc {

    return func(c *gin.Context) {

        c.Next()

        statusCode := c.Writer.Status()
        if statusCode >= 400 {
            //ok this is an request with error, let's make a record for it
            //log body here
        }
    }
}

我的问题是,如何从中间件的上下文中获取响应体?

【问题讨论】:

  • 如果还没有,请检查这里提到的错误处理github.com/gin-gonic/gin/issues/274
  • 嗯,我想我明白你的意思了,我应该在上下文中附加一个错误并在中间件中处理它,对吧?但是我仍然对如何在中间件中获取响应体感到好奇,如果我需要在将响应体发送回客户端之前对响应体做些什么呢?还是有什么奇怪的要求让我不得不得到响应体?

标签: go go-gin


【解决方案1】:

您需要先拦截响应的写入并将其存储在某个地方。然后你就可以登录了。为此,您需要实现自己的 Writer 拦截 Write() 调用。

例如如下:

type bodyLogWriter struct {
    gin.ResponseWriter
    body *bytes.Buffer
}

func (w bodyLogWriter) Write(b []byte) (int, error) {
    w.body.Write(b)
    return w.ResponseWriter.Write(b)
}

func ginBodyLogMiddleware(c *gin.Context) {
    blw := &bodyLogWriter{body: bytes.NewBufferString(""), ResponseWriter: c.Writer}
    c.Writer = blw
    c.Next()
    statusCode := c.Writer.Status()
    if statusCode >= 400 {
        //ok this is an request with error, let's make a record for it
        // now print body (or log in your preferred way)
        fmt.Println("Response body: " + blw.body.String())
    }
}

然后像这样使用这个中间件:

router.Use(ginBodyLogMiddleware)

请注意,此 sill 不适用于静态文件,因为 gin 似乎没有为它们使用 c.Writer。但在大多数情况下,这就是你想要的。

如果要拦截所有文件,则需要使用稍微复杂一些的方法。您需要实现一个包装器 http.Handler 而不是中间件,它将包装 gin.Engine 并使用与上所示相同的方法来拦截和记录写入 http.ResponseWriter 的任何内容。然后像这样运行 gin server:

ginRouter := gin.New()
// configure your middleware and routes as required

// Run http server as follows, where bodyLogHandler is your wrapper handler
http.ListenAndServe(bindAddress, &bodyLogHandler{wrappedHandler: ginRouter}

【讨论】:

  • 谢谢,我明白了,作者只能写,所以不能直接阅读。谢谢。
  • 谢谢,你也知道我是如何获取帖子参数的吗?
  • 如果您使用中间件方法,您可以从 gin.Context 将它们放入 ginBodyLogMiddleware 中,就像在实际处理程序中处理请求时一样。您显然无法从 bodyLogWriter' Write 函数中的响应编写器中获取它们,但您始终可以将 gin.Context 添加到 bodyLogWriter 结构中。无论如何,它都会为每个请求实例化。
  • 如果您使用 bodyLogHandler 方法,那么 http.Request 将提供给您的 ServeHTTP 函数。
  • 我怎么知道正文什么时候都写出来了?
【解决方案2】:

仅供参考

注意:如果使用c.String() 编写响应正文,请实现WriteString()

type bodyLogWriter struct {
    gin.ResponseWriter
    body *bytes.Buffer
}

func (w bodyLogWriter) Write(b []byte) (int, error) {
    w.body.Write(b)
    return w.ResponseWriter.Write(b)
}

func (w bodyLogWriter) WriteString(s string) (int, error) {
    w.body.WriteString(s)
    return w.ResponseWriter.WriteString(s)
}

func ginBodyLogMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        blw := &bodyLogWriter{body: bytes.NewBufferString(""), ResponseWriter: c.Writer}
        c.Writer = blw
        c.Next()

        fmt.Println("Response body: " + blw.body.String())
    }
}

...

// register
router := r.Group("/", ginBodyLogMiddleware())

【讨论】:

    猜你喜欢
    • 2013-01-20
    • 1970-01-01
    • 2020-10-17
    • 1970-01-01
    • 2022-01-15
    • 1970-01-01
    • 2012-01-12
    • 2019-04-13
    • 1970-01-01
    相关资源
    最近更新 更多