如果在调用http.Get(url)时发生错误,我们需要关闭响应对象吗?

huangapple go评论103阅读模式
英文:

Do we need to close the response object if an error occurs while calling http.Get(url)?

问题

在错误情况下,是否也需要关闭响应体呢?

res, err := http.Get(url)

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

defer res.Body.Close()

是的,在错误情况下也需要关闭响应体。以上代码中使用了 defer 关键字来延迟执行 res.Body.Close(),无论是否发生错误,都会确保在函数返回前关闭响应体。这样可以避免资源泄漏和提高代码的可靠性。

英文:

In the following code is it also necessary to close the response body in the error case:

res, err := http.Get(url)

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

defer res.Body.Close()

答案1

得分: 19

一般的概念是,当一个函数(或方法)有多个返回值时,其中一个是error,应该首先检查错误,只有在错误为nil时才继续执行。如果有错误,函数应该返回其他(非错误)值的零值。如果函数的行为不同,应该进行文档记录。http.Get()没有记录这种偏差。

所以应该这样处理:

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

defer res.Body.Close()
// 读取/处理响应体

注意:

正如JimB也确认的那样,如果返回的错误不是nil,即使响应不是nil,我们也不必关闭它。在重定向错误的情况下,非nil的响应可能包含有关重定向失败的上下文和更多信息。详细信息请参见下面的说明:

http.Get()大部分时间都遵循这个一般概念:如果有错误,它会返回nil的响应:

return nil, someError

然而,检查client.go,未导出的方法Client.doFollowingRedirects(),目前在第427行:

if redirectFailed {
	// Go 1兼容性的特殊情况:如果CheckRedirect函数失败,同时返回响应和错误。
	// 参见https://golang.org/issue/3795
	return resp, urlErr
}

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

另一方面,如果respnil,尝试调用resp.Body.Close()将导致运行时恐慌。

因此,如果我们想在这种情况下关闭响应体,可以这样写(只有当resp不是nil时才能关闭):

res, err := http.Get(url)
if err != nil {
    log.Printf("错误:%s\n", err)
}
if res != nil {
    defer res.Body.Close()
    // 读取/处理响应体
}

或者:

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

defer res.Body.Close()
// 读取/处理响应体

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

// http Client和Transport保证Body始终非nil,即使在没有响应体或零长度响应体的情况下。

但是,如果错误不是nil,则不必关闭非nil的响应体。

英文:

General concept is that when a function (or method) has multi return values one being an error, error should be checked first and only proceed if the error is nil. Functions should return zero values for other (non-error) values if there is an error. If the function behaves differently, it should be documented. http.Get() does not document such deviation.

So it should be handled like this:

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

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

Notes:

As JimB confirms too, if a non-nil error is returned, even if the response is non-nil, we don't have to close it. In case of a redirection error the non-nil response may hold context and further information about where following the redirect failed. See details below:

http.Get() honors the general concept "most of the time": it returns nil response if there is an error:

return nil, someError

However checking client.go, unexported method Client.doFollowingRedirects(), currently line #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
}

So due to a backward compatibility issue it may return a non-nil response and a non-nil error at the same time, if redirection fails.

On the other hand trying to call resp.Body.Close() if resp is nil will cause a run-time panic.

So if we want to close response body in this case, it could look like this (can only be closed if resp is not 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
}

Or:

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

The doc of http.Response guarantees that Response.Body will not be nil even if there is no response data:

// 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 if the error is not nil, you don't have to close the non-nil response body.

huangapple
  • 本文由 发表于 2015年9月28日 16:17:22
  • 转载请务必保留本文链接:https://go.coder-hub.com/32818472.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定