dongnan1989 2017-05-15 09:41
浏览 312
已采纳

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

Say I have this http handler:

func SomeHandler(w http.ResponseWriter, r *http.Request) {
    data := GetSomeData()
    _, err := w.Write(data)
}

Should I check the error returned by w.Write? Examples I've seen just ignore it and do nothing. Also, functions like http.Error() do not return an error to be handled.

  • 写回答

1条回答 默认 最新

  • doudg60800 2017-05-15 10:03
    关注

    It's up to you. My advice is that unless the documentation of some method / function explicitly states that it never returns a non-nil error (such as bytes.Buffer.Write()), always check the error and the least you can do is log it, so if an error occurs, it will leave some mark which you can investigate should it become a problem later.

    This is also true for writing to http.ResponseWriter.

    You might think ResponseWriter.Write() may only return errors if sending the data fails (e.g. connection closed), but that is not true. The concrete type that implements http.ResponseWriter is the unexported http.response type, and if you check the unexported response.write() method, you'll see it might return a non-nil error for a bunch of other reasons.

    Reasons why ResponseWriter.Write() may return a non-nil error:

    • If the connection was hijacked (see http.Hijacker): http.ErrHijacked
    • If content length was specified, and you attempt to write more than that: http.ErrContentLength
    • If the HTTP method and / or HTTP status does not allow a response body at all, and you attempt to write more than 0 bytes: http.ErrBodyNotAllowed
    • If writing data to the actual connection fails.

    Even if you can't do anything with the error, logging it may be of great help debugging the error later on. E.g. you (or someone else in the handler chain) hijacked the connection, and you attempt to write to it later; you get an error (http.ErrHijacked), logging it will reveal the cause immediately.

    Tip for "easy" logging errors

    If you can't do anything with the occasional error and it's not a "showstopper", you may create and use a simple function that does the check and logging, something like this:

    func logerr(n int, err error) {
        if err != nil {
            log.Printf("Write failed: %v", err)
        }
    }
    

    Using it:

    logerr(w.Write(data))
    

    Tip for "auto-logging" errors

    If you don't even want to use the logerr() function all the time, you may create a wrapper for http.ResponseWriter which does this "automatically":

    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
    }
    

    Using it:

    func SomeHandler(w http.ResponseWriter, r *http.Request) {
        w = LogWriter{w}
        w.Write([]byte("hi"))
    }
    

    Using LogWriter as a wrapper around http.ResponseWriter, should writes to the original http.ResponseWriter fail, it will be logged automatically.

    This also has the great benefit of not expecting a logger function to be called, so you can pass a value of your LogWriter "down" the chain, and everyone who attempts to write to it will be monitored and logged, they don't have to worry or even know about this.

    But care must be taken when passing LogWriter down the chain, as there's also a downside to this: a value of LogWriter will not implement other interfaces the original http.ResponseWriter might also do, e.g. http.Hijacker or http.Pusher.

    Here's an example on the Go Playground that shows this in action, and also shows that LogWriter will not implement other interfaces; and also shows a way (using 2 "nested" type assertions) how to still get out what we want from LogWriter (an http.Pusher in the example).

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 如何在scanpy上做差异基因和通路富集?
  • ¥20 关于#硬件工程#的问题,请各位专家解答!
  • ¥15 关于#matlab#的问题:期望的系统闭环传递函数为G(s)=wn^2/s^2+2¢wn+wn^2阻尼系数¢=0.707,使系统具有较小的超调量
  • ¥15 FLUENT如何实现在堆积颗粒的上表面加载高斯热源
  • ¥30 截图中的mathematics程序转换成matlab
  • ¥15 动力学代码报错,维度不匹配
  • ¥15 Power query添加列问题
  • ¥50 Kubernetes&Fission&Eleasticsearch
  • ¥15 報錯:Person is not mapped,如何解決?
  • ¥15 c++头文件不能识别CDialog