当 http.ResponseWriter 被 flush 或 end 时,处理函数会被执行。

huangapple go评论82阅读模式
英文:

Handler function execution upon http.ResponseWriter flush/end?

问题

有没有一种方法可以在http.ResponseWriter上挂接到flush/end事件,以便在发送之前执行一个处理程序,该处理程序会向writer写入更多内容。

英文:

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.

答案1

得分: 3

你可以简单地包装你的HandleFunc,在包装的处理程序返回后,你可以向ResponseWriter写入更多的数据:

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

func wrapper(w http.ResponseWriter, r *http.Request) {
    myhandler(w, r)           // 调用原始处理程序
    w.Write([]byte(" World")) // 向输出写入更多的数据
}

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

访问任何URL都会得到以下响应:

Hello World

在生产环境中需要注意的事项:

  • 包装器还应检查包装处理程序的响应代码或成功情况,并根据情况采取行动(例如,如果提供了错误页面,则可能不希望继续执行附加写入)。
  • 如果被包装的处理程序设置了"Content-length"头部,写入更多的数据将使其无效(因为内容将比头部中指示的大小更大)。

对此的一种可能的"保护"是传递一个自定义的ResponseWriter实现,该实现仅写入到缓冲区(例如bytes.Buffer),并且包装器将附加到此缓冲区并根据新长度设置"Content-length",然后将缓冲区的内容写入"真正的"输出。

英文:

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.

答案2

得分: 2

你可以创建自己的http.ResponseWriter来实现这个功能,或者你可以使用一个"中间件模式":

// foo 是主要的处理器
type foo struct{}

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

// bar 在 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 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.

huangapple
  • 本文由 发表于 2015年11月16日 19:11:46
  • 转载请务必保留本文链接:https://go.coder-hub.com/33733974.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定