Logging responses to incoming HTTP requests inside http.HandleFunc

前端 未结 3 2042
慢半拍i
慢半拍i 2020-12-10 17:38

This is a follow-up question to In go, how to inspect the http response that is written to http.ResponseWriter? since the solution there requires faking a request, which wor

3条回答
  •  攒了一身酷
    2020-12-10 18:27

    This can be achieved by using a custom ServerMux that does no routing, but replaces the response writer, and then forwards the request to a normal mux. Since ResponseWriter is just an interface we can fake it easily.

    First, we wrap the ResponseWriter interface with our own response writer, that will log everything and pass all functionality to a real response writer:

    type DumpResponseWriter struct {
        // the underlying writer
        w http.ResponseWriter
        // more stuff you want to use for logging context (ip, headers, etc) here
    }
    
    
    func (w *DumpResponseWriter)Header() http.Header {
        return w.w.Header()
    }
    
    func (w *DumpResponseWriter)Write(b []byte) (int, error) {
            // You can add more context about the connection when initializing the writer and log it here
            log.Println("Writing < more context details here> ", string(b) )
            return w.w.Write(b)
    }
    
    
    func (w *DumpResponseWriter)WriteHeader(h int) {
        log.Println("Writing Header< more context details here> ", h)
        w.w.WriteHeader(h)
    }
    

    This leaves our handler func the same as before, and agnostic to the fact that we're using a "Fake" writer...

    func MyHandler(w http.ResponseWriter, r *http.Request) {
    
        w.Write([]byte("Hello world"))
    }
    

    And then we simply replace the default mux with our own proxy mux, that replaces the writer and lets a regular ServeMux do its thing:

    func main(){
    
        // we don't use the default mux, but a custom one
        mux := http.NewServeMux()
        mux.HandleFunc("/", MyHandler)
    
        // now we intercept each request and forward it to the mux to do    the routing to the handlers.
        err := http.ListenAndServe(":1337", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        // we wrap the response writer with our own. Add more context here if you want to the writer's instance
            writer := &DumpResponseWriter{w}
    
            // and we let our ordinary mux take care of things from here
            mux.ServeHTTP(writer, r)
    
            // We can also dump the headers after the handler is done. It will not print the standard headers though
            log.Printf("Response headers: %#v", w.Header())
    
        }))
        if err != nil {
            panic(err)
        }
    }
    

    http://play.golang.org/p/hT1PCNxI-V

提交回复
热议问题