func SomeHandler(w http.ResponseWriter, r *http.Request) { data := GetSomeData() _, err := w.Write(data) }
我应该检查w.Write返回的错误吗?我见过的例子只是忽略它而什么都不做.此外,像http.Error()这样的函数不会返回要处理的错误.
由你决定.我的建议是,除非某些方法/函数的文档明确声明它永远不会返回非零错误(例如bytes.Buffer.Write()
),否则总是检查错误,并且您可以做的最少是记录它,所以如果发生错误,它如果以后出现问题,你会留下一些标记.
写入http.ResponseWriter
也是如此.
您可能认为ResponseWriter.Write()可能仅在发送数据失败时返回错误(例如,连接已关闭),但事实并非如此.实现http.ResponseWriter的具体类型是未导出的http.response类型,如果检查未导出的response.write()方法,您会看到它可能由于其他一些原因而返回非零错误.
ResponseWriter.Write()可能返回非零错误的原因:
>如果连接被劫持(见http.Hijacker
):http.ErrHijacked
>如果指定了内容长度,并且您尝试编写的内容超过:http.ErrContentLength
>如果HTTP方法和/或HTTP状态根本不允许响应主体,并且您尝试写入超过0个字节: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)中获取我们想要的内容.