说我有这个http处理程序:
func SomeHandler(w http.ResponseWriter, r *http.Request) {
data := GetSomeData()
_, err := w.Write(data)
}
我应该检查w.Write
返回的错误吗?我见过的例子只是忽略它而什么都不做。此外,http.Error()
等函数不会返回要处理的错误。
答案 0 :(得分:15)
这取决于你。我的建议是,除非某些方法/函数的文档明确声明它永远不会返回非nil
错误(例如bytes.Buffer.Write()
),否则请始终检查错误,并且您可以做的最少是记录它,所以如果发生错误,它会留下一些标记,如果以后出现问题你可以调查。
写入http.ResponseWriter
时也是如此。
如果发送数据失败(例如连接已关闭),您可能认为ResponseWriter.Write()
可能只返回错误,但事实并非如此。实现http.ResponseWriter
的具体类型是未导出的http.response
类型,如果您检查未导出的response.write()
方法,您会看到它可能会返回非nil
错误其他一些原因。
ResponseWriter.Write()
可能会返回非nil
错误的原因
http.Hijacker
):http.ErrHijacked
http.ErrContentLength
http.ErrBodyNotAllowed
即使您无法对错误做任何事情,记录它可能对以后调试错误有很大帮助。例如。你(或处理程序链中的其他人)劫持了连接,你试图稍后写信给它;你得到一个错误(http.ErrHijacked
),记录它会立即显示原因。
如果您不能对偶然的错误做任何事情并且它不是“showstopper”,您可以创建并使用一个执行检查和记录的简单函数,如下所示:
func logerr(n int, err error) {
if err != nil {
log.Printf("Write failed: %v", err)
}
}
使用它:
logerr(w.Write(data))
如果您甚至不想一直使用logerr()
函数,可以为http.ResponseWriter
创建一个“自动”执行此操作的包装器:
type LogWriter struct {
http.ResponseWriter
}
func (w LogWriter) Write(p []byte) (n int, err error) {
n, err = w.ResponseWriter.Write(p)
if err != nil {
log.Printf("Write failed: %v", err)
}
return
}
使用它:
func SomeHandler(w http.ResponseWriter, r *http.Request) {
w = LogWriter{w}
w.Write([]byte("hi"))
}
使用LogWriter
作为http.ResponseWriter
的包装,如果写入原始http.ResponseWriter
失败,则会自动记录。
这样做的好处还在于不会期望调用记录器功能,因此您可以将LogWriter
“向下”传递给链,并且每个尝试写入记录器的人都将受到监控,记录下来,他们不必担心甚至不知道这一点。
但是在将LogWriter
传递给链时必须小心,因为这也有一个缺点:LogWriter
的值不会实现原始http.ResponseWriter
可能也会执行的其他接口,例如http.Hijacker
或http.Pusher
。
以下是Go Playground中显示此操作的示例,并且还显示LogWriter
不会实现其他接口;并且还显示了一种方法(使用2个“嵌套”类型断言)如何从LogWriter
(示例中的http.Pusher
)中得到我们想要的内容。
答案 1 :(得分:-1)
我想添加到@icza 解决方案中。你不需要创建日志结构,你可以使用简单的函数:
func logWrite(write func([]byte) (int, error), body []byte) {
_, err := write(body)
if err != nil {
log.Printf("Write failed: %v", err)
}
}
看看基于@icza 代码的方法:https://play.golang.org/p/PAetVixCgv4