记录 http.ResponseWriter 内容
log http.ResponseWriter content
前提:我发现了一个类似的问题,但在我的案例中不起作用,所以请不要将其标记为重复。
我在 Go 中有一个 HTTP 服务器,我创建了一个 中间件 来记录请求、响应时间,我也想记录响应。
我在包 log
下的一个名为 HTTPRequest
的函数中使用了 httputil.DumpRequest
。
我怎样才能正确地从 w http.ResponseWriter
获得响应 body 和状态以及 headers 并将它们与其他数据一起记录?
我的问题是:我想拦截响应 Headers、状态和 Body 并与请求和响应时间一起记录
代码如下:
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)
})
}
您需要包装 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)
})
}
谢谢,@Sivachandran 的回复。它几乎是完美的,只是它没有实现 http.ResponseWriter
因为指针。
为了完整起见,我post在这里给出了正确的解决方案代码,因为很难找到关于它的任何文档,即使这道题被打了负分。
Whosebug 是交流问题的好地方,在我看来,这是一个 非常好的问题,无论是对于一个中等水平的 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()
}
前提:我发现了一个类似的问题,但在我的案例中不起作用,所以请不要将其标记为重复。
我在 Go 中有一个 HTTP 服务器,我创建了一个 中间件 来记录请求、响应时间,我也想记录响应。
我在包 log
下的一个名为 HTTPRequest
的函数中使用了 httputil.DumpRequest
。
我怎样才能正确地从 w http.ResponseWriter
获得响应 body 和状态以及 headers 并将它们与其他数据一起记录?
我的问题是:我想拦截响应 Headers、状态和 Body 并与请求和响应时间一起记录
代码如下:
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)
})
}
您需要包装 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)
})
}
谢谢,@Sivachandran 的回复。它几乎是完美的,只是它没有实现 http.ResponseWriter
因为指针。
为了完整起见,我post在这里给出了正确的解决方案代码,因为很难找到关于它的任何文档,即使这道题被打了负分。
Whosebug 是交流问题的好地方,在我看来,这是一个 非常好的问题,无论是对于一个中等水平的 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()
}