我应该在响应正文上错误检查Close()吗?

rco*_*rre 14 go

文档net/http包含以下示例:

resp, err := http.Get("http://example.com/")
if err != nil {
    panic(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
fmt.Printf("%s", body)
Run Code Online (Sandbox Code Playgroud)

Close返回一个error,但没有检查.这里有什么我想念的吗?在go中经常强调检查每个错误的重要性,但我看到这种defer resp.Body.Close()模式很多,没有错误检查.

Adr*_*ian 14

有两件事需要考虑:如果你检查它并且出现错误,你会怎么做?而且,如果出现错误会有什么副作用?

在大多数情况下,对于关闭响应机构,这两个问题的答案都是......绝对没有.如果出现错误并且错误没有明显影响,那么你什么都不做,没有理由检查它.

另请注意,Close()为了实现io.Closer接口,返回错误; 该函数不一定会返回错误.您需要检查源以确定是否存在错误情况.

  • @rcorre,虽然我和 Adrian 在一起,但请注意,上述所有内容仅适用于 HTTP 响应的主体——不要盲目地将其应用于所有内容!特别是,始终检查在为写入而打开的文件上调用的 `Close()` 中可能出现的错误!有关解释,请阅读 [`open(2)` 手册页](https://manpages.debian.org/stretch/manpages-dev/close.2.en.html#Dealing_with_error_returns_from_close%28%29)。 (2认同)

Mih*_*ilo 9

这是使用的缺点 defer

建议您作为负责任的开发人员,检查所有可能的容易出错的点,并尽可能优雅地处理它们。

您可以在处理这种情况时选择以下选项:

选项1

不要使用defer,而是在完成响应主体后手动调用close,然后简单地检查是否有错误。

选项#2

创建一个包装结束和错误检查代码的匿名函数。像这样:

defer func() {
    err := resp.Body.Close()
    if err != nil {
        log.Fatal(err)
    }
}()
Run Code Online (Sandbox Code Playgroud)

避免panics在程序中使用。尝试通过执行某些操作或至少记录错误来优雅地处理错误。


可以在此处找到更多信息。


k1m*_*90r 5

要添加到 @Mihailo 选项 #2,请将其称为选项 #2.1 定义函数,dclose()如下所示:

func dclose(c io.Closer) {
    if err := c.Close(); err != nil {
        log.Fatal(err)
    }
}
Run Code Online (Sandbox Code Playgroud)

像这样使用:

defer dclose(resp.Body)
Run Code Online (Sandbox Code Playgroud)

另外,在您的代码中,检查err!=nil可以声明:

func errcheck(err error) {
    if err != nil {
        log.Fatal(err)
    }
}
Run Code Online (Sandbox Code Playgroud)

然后使用:

errcheck(err)
Run Code Online (Sandbox Code Playgroud)

那么你的代码就变成:

resp, err := http.Get("http://example.com/")
errcheck(err)
defer dclose(resp.Body)

body, err := ioutil.ReadAll(resp.Body)
errcheck(err)

fmt.Printf("%s", string(body))
Run Code Online (Sandbox Code Playgroud)

恕我直言,也许更干净一点?但我会等待go爱好者纠正我并强调缺点。

编辑

谢谢!@RayfenWindspear

请更换log.Fatal(err)log.Println(err)避免不必要的恐慌。

编辑2

dclose()以避免与 go 混淆close()

玩得开心!

  • 这类事情对于简单的错误情况非常有用。它对于清理游乐场示例特别有用。但在生产中很多时候,每个错误的处理方式通常不同,这可能会使命名空间与“errcheckJSON”或“errcheck1”混乱(但可能不是“Close”的情况)。不关注你的答案,只是注意一般错误情况的局限性。对我来说“关闭”似乎很好,尽管我会使用更像这样的东西 https://play.golang.org/p/nzGTFe81g_ 而不是引起恐慌。 (3认同)