在以下代码中,在错误情况下也有必要关闭响应主体:

res, err := http.Get(url)

if err != nil {
    log.Printf("Error: %s\n", err)
}

defer res.Body.Close()

推荐答案

一般概念是,当一个函数(或方法)有多个返回值(其中一个是error)时,应该首先判断错误,并且只有在错误是nil的情况下才会继续.如果存在error,则函数应为其他(非错误)值返回零值.如果该函数的行为不同,则应对其进行记录.http.Get()不记录此类偏差.

所以应该这样处理:

res, err := http.Get(url)
if err != nil {
    log.Printf("Error: %s\n", err)
    return
}

defer res.Body.Close()
// Read/work with body

Notes:

正如jimB也确认的那样,如果返回非nil错误,即使响应为非nil,我们也不必关闭它.在重定向错误的情况下,非nil响应可以保存上下文和关于随后重定向失败的位置的进一步信息.请参阅以下详细信息:

http.Get()遵循"大多数时间"的一般概念:如果出现错误,它将返回nil响应:

return nil, someError

但是,判断client.go,未导出的方法Client.doFollowingRedirects(),当前行#427:

if redirectFailed {
    // Special case for Go 1 compatibility: return both the response
    // and an error if the CheckRedirect function failed.
    // See https://golang.org/issue/3795
    return resp, urlErr
}

因此,由于向后兼容性问题,如果重定向失败,它可能会同时返回非nil响应和非nil错误.

另一方面,如果respnil,try 拨打resp.Body.Close()会导致运行时panic .

因此,如果我们想在本例中关闭响应正文,它可能如下所示(只有在resp不是nil的情况下才能关闭):

res, err := http.Get(url)
if err != nil {
    log.Printf("Error: %s\n", err)
}
if res != nil {
    defer res.Body.Close()
    // Read/work with body
}

或者:

res, err := http.Get(url)
if err != nil {
    log.Printf("Error: %s\n", err)
}
if res == nil {
    return
}

defer res.Body.Close()
// Read/work with body

http.Response的doc保证即使没有响应数据,Response.Body也不会是nil:

// The http Client and Transport guarantee that Body is always
// non-nil, even on responses without a body or responses with
// a zero-length body.

But如果错误不是nil,则不必关闭非nil响应正文.

Go相关问答推荐

golang 的通用 map 功能

使用ciph.AEAD.Seal()查看内存使用情况

Go Colly-访问for循环中的URL

如何在围棋中从多部分.Part中获取多部分.文件而不保存到磁盘?

Go安装成功但没有输出简单的Hello World

使用 goroutine 比较 Golang 中的两棵树是等价的

使用Dockertest进行Golang SQL单元测试的基本设置

为什么docall在singleflight中使用go panic?

为什么 net/http 不遵守超过 30 秒的超时持续时间?

如何以干净的方式在中间件中注入 repo 或服务?

Golang - POST 失败(NoSurf CSRF)

Neptune 在连接到启用 IAM 的 Neptune 实例时抛出握手错误错误

为什么不同的 Wireguard 私钥会产生相同的公钥?

Golang并发写入多个文件

如何使用特定的 Go 版本运行 govulncheck?

try 与 golang testify/suite 并行运行测试失败

如何在测试中使用自定义标志(使用`testify/suite`)

Go 导入范围查找 protobuf 类型

不能使用 *T 类型的变量作为参数类型

try 创建新的 etcdv3 客户端时出现pc error: code = Unavailable desc = error reading from server: EOF