在http.ResponseWriter刷新/结束时执行处理程序函数吗?

Is there a way to hook onto a flush/end event on an http.ResponseWriter in order to execute a handler which writes more to the writer just before sending.

You could create your own http.ResponseWriter to do that, or you could just use a "middleware pattern":

// foo is the main handler
type foo struct{}

func (foo) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("foo"))
}

// bar writes after foo
type bar struct {
    h http.Handler
}

func (b bar) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    b.h.ServeHTTP(w, r)
    w.Write([]byte("BAR"))
}

Playground: http://play.golang.org/p/fB2OXNSTIe.

You can simply wrap your HandleFunc, and after the wrapped handler returns, you can write further data to the ResponseWriter:

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

func wrapper(w http.ResponseWriter, r *http.Request) {
    myhandler(w, r)           // Call original
    w.Write([]byte(" World")) // Write further data to output
}

func main() {
    http.HandleFunc("/", wrapper)
    http.ListenAndServe("", nil)
}

Visiting any URL will result in response:

Hello World

Things to keep in mind in production environment:

  • The wrapper should also examine response code or success of the wrapped handler, and act upon (e.g. if an error page is served, it might not be desired to still carry out the additional write).
  • If "Content-length" header is set by the wrapped handler, writing more data will render it invalid (as the content will be bigger than indicated in the header).

One possible "protection" against this might be to pass a custom ResponseWriter implementation which writes only to a buffer (e.g. bytes.Buffer) and the wrapper will append to this and set "Content-length" according to the new length, and then write the content of the buffer to the "real" output.