Go 如何在gin中记录响应体

Go 如何在gin中记录响应体,go,go-gin,Go,Go Gin,我需要在gin的中间件中记录响应体,但我找不到如何获取响应体。有人能帮忙吗 我使用的中间件如下所示: func Logger() gin.HandlerFunc { return func(c *gin.Context) { c.Next() statusCode := c.Writer.Status() if statusCode >= 400 { //ok this is an request wit

我需要在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
        }
    }
}
router.Use(ginBodyLogMiddleware)
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}

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

您需要拦截响应的写入并首先将其存储在某个位置。然后你可以把它记录下来。要做到这一点,您需要实现自己的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())
    }
}
然后像这样使用该中间件:

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
        }
    }
}
router.Use(ginBodyLogMiddleware)
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似乎没有对它们使用c.Writer。但在大多数情况下,这正是你想要的

如果要截取所有文件,需要使用稍微复杂一点的方法。您需要实现一个包装器http.Handler,而不是中间件,它将包装gin.Engine,并使用与上面所示相同的方法来拦截和记录写入http.ResponseWriter的内容。然后按如下方式运行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
        }
    }
}
router.Use(ginBodyLogMiddleware)
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}
供参考

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

类型bodyLogWriter结构{
杜松子酒应答器
body*bytes.Buffer
}
func(带bodyLogWriter)写入(b[]字节)(int,错误){
w、 正文(b)
返回w.ResponseWriter.Write(b)
}
func(带bodyLogWriter)WriteString(s字符串)(int,error){
w、 正文.书面限制(s)
返回w.ResponseWriter.WriteString(s)
}
func ginBodyLogMiddleware()gin.HandlerFunc{
返回函数(c*gin.Context){
blw:=&bodyLogWriter{body:bytes.NewBufferString(“”),ResponseWriter:c.Writer}
c、 Writer=blw
c、 下一个()
fmt.Println(“响应主体:+blw.body.String())
}
}
...
//登记册
路由器:=r.Group(“/”,ginBodyLogMiddleware()

如果还没有,请检查这里提到的错误处理嗯,我想我明白你的意思了,我应该在上下文中附加一个错误并在中间件中处理,对吗?但我仍然对如何在中间件中获得响应体感到好奇,如果在将响应体发送回客户端之前需要在响应体上做些什么呢?或者任何奇怪的要求让我不得不得到回复体?谢谢,我明白了,作者只能写,所以我不能直接读。Thnaks.谢谢,你知道我是如何获得post参数的吗?如果你使用中间件方法,你可以从gin.Context在ginBodyLogMiddleware中获得它们,就像在实际处理程序中处理请求时获得它们一样。显然,您无法从bodyLogWriter的Write函数中的response writer获取它们,但您始终可以将gin.Context添加到bodyLogWriter结构中。不管怎样,它都会为每个请求实例化。如果您使用的是bodyLogHandler方法,那么http.request将提供给您的ServeHTTP函数。我如何知道主体何时全部写出?