英文:
How can I tell if net/http's ResponseWriter.Write() has been called?
问题
假设我有一系列的net/http处理程序,并且其中一个处理程序以HTTP错误(例如http.StatusInternalServerError
)进行响应。我如何在后续的处理程序中检测到这个错误,并避免向客户端发送额外的数据?
或者,这完全是错误的解决方法吗?
英文:
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 the following handlers, and avoid sending additional data to the client?
Or is this entirely the wrong approach to the problem?
答案1
得分: 6
http.ResponseWriter
是一个接口。所以只需组合一个新的实例:
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)
}
在你的处理程序中:
//...
if w, ok := w.(*MyResponseWriter); ok && w.WroteHeader {
log.Println("已经写入,跳过")
return
}
编辑: 还有一件事要考虑。大多数情况下,如果你有一个“链”式处理程序,这意味着一个处理程序在另一个处理程序内部被调用。所以如果你有像下面这样的东西:
type Handler1 struct { http.Handler }
type Handler2 struct { http.Handler }
type Handler3 struct { http.Handler }
var MyHandler http.Handler = Handler1{Handler2{Handler3{h}}}
只要每个处理程序在使用w
和r
之后作为它们与内部处理程序的最后一件事情调用内部处理程序,你应该没问题,因为w
和r
甚至不会到达内部处理程序。例如:
func (h Handler2) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if somethingBadHappened() {
w.WriteHeader(http.StatusInternalServerError)
return
}
h.ServeHTTP(w, r) // 如果somethingBadHappened()没有被调用,则不会执行此行。
}
希望对你有所帮助!
英文:
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().
}
答案2
得分: 0
首先,可能存在一种更轻量级的解决方案。
但是,如果你找不到这样的解决方案,可以考虑使用x/net/context
来实现超时、截止日期以及中间件链的提前终止。
英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论