转到HTTP ListenAndServe日志记录响应

I was wondering if there is a way to log the responses when using ListenAndServe.

As far as I can tell, the handler doesn't have access to a "Response" object. Just a ResponseWriter, so I cannot call httputil.DumpResponse.

http.ResponseWriter is an interface. You can use embedding to extend it for logging as follows.

package main
import (
    "log"
    "net/http"
)

func sampleHandler(w http.ResponseWriter, r *http.Request) {
    w.WriteHeader(http.StatusOK)
    response := []byte("Sample Response")
    w.Write(response)
}

type loggingResponseWriter struct {
    status int
    body   string
    http.ResponseWriter
}

func (w *loggingResponseWriter) WriteHeader(code int) {
    w.status = code
    w.ResponseWriter.WriteHeader(code)
}

func (w *loggingResponseWriter) Write(body []byte) (int, error) {
    w.body = string(body)
    return w.ResponseWriter.Write(body)
}

func responseLogger(h http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        loggingRW := &loggingResponseWriter{
            ResponseWriter: w,
        }
        h.ServeHTTP(loggingRW, r)
        log.Println("Status : ", loggingRW.status, "Response : ", loggingRW.body)
    })
}

func main() {
    http.Handle("/", responseLogger(http.HandlerFunc(sampleHandler)))
    http.ListenAndServe(":8080", nil)
}

You can wrap the handler functions that you want to log responses for with responseLogger.

You can't because the response technically doesn't exist until you write it to the ResponseWriter.

But in the response is just the header, body and response code so in the handler function you can use method Header() on the ResponseWriter to get the header and then you can log the response code and the body before you write it to the ResponseWriter.

If you provide an example of what you are trying to do, I can elaborate on how to do it.

This is what I did to fix this for a small project: I use this in all my handlers:

type transaction struct {
    res Response // Create this type also
    req Request // Create this type also
}

func NewTransaction(w http.ResponseWriter, req *http.Request) *transaction{}

Log := make(chan transaction, 100)
go func{
    // Read from channel and log the info however you want.
}()

func indexHandler(w http.ResponseWriter, req *http.Request) {
    tx := NewTransaction(w, req) // Struct with the request and response
    defer func() {
        Log <- tx
    }()

    /*
    Handle request here
    */

    // Update request and response
    Request.Body = body
}

And at the end of the handler function, after having served the requested data, I update the values for the request and the response.

And have a goroutine listening to the channel Log and doing all your logging.

Also you can write a wrapper function that serves the file and returns the response.

As an alternative, one can use fasthttp.