【问题标题】:log http.ResponseWriter content记录 http.ResponseWriter 内容
【发布时间】:2021-06-06 05:46:41
【问题描述】:

前提:我发现了一个类似的问题,但不适用于我的情况,所以请不要将其标记为重复。

我在 Go 中有一个 HTTP 服务器,我创建了一个中间件来记录请求、响应时间,我也想记录响应。

我在log 包下的一个名为HTTPRequest 的函数中使用了httputil.DumpRequest。 如何从w http.ResponseWriter 正确获取响应正文、状态和标头并将它们与其他数据一起记录?

我的问题是:我想截取响应标头、状态和正文并将它们与请求和响应时间一起记录

代码如下:

log "core/logger"
...
func RequestLoggerMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        start := time.Now()

        defer func() {
            log.Info(
                fmt.Sprintf(
                    "[Request: %s] [Execution time: %v] [Response: %s]",
                    log.HTTPRequest(r),
                    time.Since(start),
                    // RESPONSE DATA HERE !!!!!!!
                ))
        }()
        next.ServeHTTP(w, r)
    })
}

【问题讨论】:

  • 您的代码面临什么问题?您看到什么错误或其他不良行为?您需要什么帮助?
  • 如果不清楚,我会编辑
  • 现在清楚一点了。谢谢。你试过什么?
  • 我试过这个:stackoverflow.com/questions/43801849/… 和一个 HttpRecorder 但我根本没有找到有效的解决方案。
  • 尽你最大的努力更新你的代码,并解释什么不起作用。

标签: go logging middleware


【解决方案1】:

您需要包装ResponseWriter 以捕获响应数据。

type ResponseWriterWrapper struct {
  w           http.ResponseWriter
  body        bytes.Buffer
  statusCode  int
}

func (i *ResponseWriterWrapper) Write(buf []byte) (int, error) {
  i.body.Write(buf)
  return i.w.Write(buf)
}

func (i *ResponseWriterWrapper) WriteHeader(statusCode int) {
  i.statusCode = statusCode
  i.w.WriteHeader(statusCode)
}

func (i *ResponseWriterWrapper) String() {
  var buf bytes.Buffer

  buf.WriteString("Response:")

  buf.WriteString("Headers:")
  for k, v := range i.w.Header() {
    buf.WriteString(fmt.Sprintf("%s: %v", k, v))
  }

  buf.WriteString(fmt.Sprintf("Status Code: %d", i.statusCode))

  buf.WriteString("Body")
  buf.WriteString(i.body.String())
}

将包装器传递给ServeHTTP 并记录捕获的响应数据。

func RequestLoggerMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        start := time.Now()
        rww := ResponseWriterWrapper{ w: w }

        defer func() {
            log.Info(
                fmt.Sprintf(
                    "[Request: %s] [Execution time: %v] [Response: %s]",
                    log.HTTPRequest(r),
                    time.Since(start),
                    log.Info(rww.String())
                ))
        }()
        next.ServeHTTP(rww, r)
    })
}

【讨论】:

    【解决方案2】:

    感谢 @Sivachandran 的回复。它几乎是完美的,只是它没有实现 http.ResponseWriter 因为指针。

    为了完整起见,我在这里发布正确的解决方案代码,因为即使这个问题被给予负分,也不容易找到任何关于它的文档。

    Stackoverflow 是一个交换问题的好地方,在我看来,这是一个非常好的和困难的问题,对于中级 Golang 程序员来说,所以它根本不应该得到负分

    这就是解决方案,享受吧:

    // RequestLoggerMiddleware is the middleware layer to log all the HTTP requests
    func RequestLoggerMiddleware(next http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            start := time.Now()
            rww := NewResponseWriterWrapper(w)
            w.Header()
            defer func() {
                log.Info(
                    fmt.Sprintf(
                        "[Request: %s] [Execution time: %v] [Response: %s]",
                        log.HTTPRequest(r),
                        time.Since(start),
                        rww.String(),
                    ))
            }()
            next.ServeHTTP(rww, r)
        })
    }
    
    // ResponseWriterWrapper struct is used to log the response
    type ResponseWriterWrapper struct {
        w          *http.ResponseWriter
        body       *bytes.Buffer
        statusCode *int
    }
    
    // NewResponseWriterWrapper static function creates a wrapper for the http.ResponseWriter
    func NewResponseWriterWrapper(w http.ResponseWriter) ResponseWriterWrapper {
        var buf bytes.Buffer
        var statusCode int = 200
        return ResponseWriterWrapper{
            w:          &w,
            body:       &buf,
            statusCode: &statusCode,
        }
    }
    
    func (rww ResponseWriterWrapper) Write(buf []byte) (int, error) {
        rww.body.Write(buf)
        return (*rww.w).Write(buf)
    }
    
    // Header function overwrites the http.ResponseWriter Header() function
    func (rww ResponseWriterWrapper) Header() http.Header {
        return (*rww.w).Header()
    
    }
    
    // WriteHeader function overwrites the http.ResponseWriter WriteHeader() function
    func (rww ResponseWriterWrapper) WriteHeader(statusCode int) {
        (*rww.statusCode) = statusCode
        (*rww.w).WriteHeader(statusCode)
    }
    
    func (rww ResponseWriterWrapper) String() string {
        var buf bytes.Buffer
    
        buf.WriteString("Response:")
    
        buf.WriteString("Headers:")
        for k, v := range (*rww.w).Header() {
            buf.WriteString(fmt.Sprintf("%s: %v", k, v))
        }
    
        buf.WriteString(fmt.Sprintf(" Status Code: %d", *(rww.statusCode)))
    
        buf.WriteString("Body")
        buf.WriteString(rww.body.String())
        return buf.String()
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-10-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-01
      • 2013-11-24
      • 1970-01-01
      • 2011-04-09
      相关资源
      最近更新 更多