How can I tell if net/http's ResponseWriter.Write() has been called?

前端 未结 2 708
无人及你
无人及你 2021-01-21 06:35

Suppose I have a chain of net/http Handlers, and an early one responds with an HTTP error (http.StatusInternalServerError, for instance). How can I detect this in

相关标签:
2条回答
  • 2021-01-21 06:58

    http.ResponseWriter is an interface. So just compose a new instance of it:

    type MyResponseWriter struct {
        http.ResponseWriter
        WroteHeader bool
    }
    
    func (w *MyResponseWriter) Write(b []byte) (int, error) {
        w.WroteHeader = true
        return w.ResponseWriter.Write(b)
    }
    
    func (w *MyResponseWriter) WriteHeader(code int) {
        w.WroteHeader = true
        w.ResponseWriter.WriteHeader(code)
    }
    

    And in your handlers:

    //...
    if w, ok := w.(*MyResponseWriter); ok && w.WroteHeader {
        log.Println("Already wrote, skipping")
        return
    }
    

    EDIT: Another thing to consider. Most of the time if you have a "chain" of handlers that means that a handler is called inside a handler. So if you have something like

    type Handler1 struct { http.Handler }
    type Handler2 struct { http.Handler }
    type Handler3 struct { http.Handler }
    var MyHandler http.Handler = Handler1{Handler2{Handler3{h}}}
    

    as long as each of those call the inner handler as the last thing they do with w and r, you should be fine because then w and r won't even reach the inner handler. E.g.

    func (h Handler2) ServeHTTP(w http.ResponseWriter, r *http.Request) {
        if somethingBadHappened() {
            w.WriteHeader(http.StatusInternalServerError)
            return
        }
        h.ServeHTTP(w, r) // Not called if somethingBadHappened().
    }
    
    0 讨论(0)
  • 2021-01-21 07:02

    First: a lighter-weight solution may exist.

    However, if you cannot find one, consider using x/net/context to allow you to implement timeouts, deadlines, and of course, early termination of middleware chains.

    0 讨论(0)
提交回复
热议问题