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 win10权限管理,限制普通用户使用删除功能
  • ¥15 minnio内存占用过大,内存没被回收(Windows环境)
  • ¥65 抖音咸鱼付款链接转码支付宝
  • ¥15 ubuntu22.04上安装ursim-3.15.8.106339遇到的问题
  • ¥15 求螺旋焊缝的图像处理
  • ¥15 blast算法(相关搜索:数据库)
  • ¥15 请问有人会紧聚焦相关的matlab知识嘛?
  • ¥15 网络通信安全解决方案
  • ¥50 yalmip+Gurobi
  • ¥20 win10修改放大文本以及缩放与布局后蓝屏无法正常进入桌面