当前位置 : 主页 > 网页制作 > HTTP/TCP >

调用http.ResponseWriter.Write()时检查错误

来源:互联网 收集:自由互联 发布时间:2021-06-16
说我有这个http处理程序: func SomeHandler(w http.ResponseWriter, r *http.Request) { data := GetSomeData() _, err := w.Write(data)} 我应该检查w.Write返回的错误吗?我见过的例子只是忽略它而什么都不做.此外
说我有这个http处理程序:

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)中获取我们想要的内容.

网友评论