从文档上http.ResponseWriter https://golang.org/pkg/net/http/#ResponseWriter方法:(强调已添加)
这应该突出说明为什么您无法在之后设置 cookienext.ServeHTTP(w, r)
调用,这是该调用执行的中间件链中的处理程序之一正在调用WriteHeader
or Write
直接或间接。
这样才能设置cookieafter the next.ServeHTTP(w, r)
调用您需要确保中间件链中没有任何处理程序调用WriteHeader
or Write
在原来的http.ResponseWriter
实例。执行此操作的一种方法是将原始实例包装在自定义实例中http.ResponseWriter
实施将postpone直到您完成 cookie 设置后才写入响应。
例如这样的事情:
type responsewriter struct {
w http.ResponseWriter
buf bytes.Buffer
code int
}
func (rw *responsewriter) Header() http.Header {
return rw.w.Header()
}
func (rw *responsewriter) WriteHeader(statusCode int) {
rw.code = statusCode
}
func (rw *responsewriter) Write(data []byte) (int, error) {
return rw.buf.Write(data)
}
func (rw *responsewriter) Done() (int64, error) {
if rw.code > 0 {
rw.w.WriteHeader(rw.code)
}
return io.Copy(rw.w, &rw.buf)
}
您可以在中间件中像这样使用它:
func handler(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
rw := &responsewriter{w: w}
next.ServeHTTP(rw, r)
if r.Method == "POST" && r.URL.String() == "/login" {
foo := rw.Header().Get("X-FOO")
setCookie(rw, "MYAPPFOO", foo)
}
if _, err := rw.Done(); err != nil {
log.Println(err)
}
})
}