不管是否使用 Resp 的内容都需要手动关闭,否则会导致进程打开的 fd 一直变多,最终系统杀掉进程,报错类似:

http: Accept error: accept tcp [::]:4200: accept4: too many open files; retrying in 1s

HTTP连接的功能由3个goroutine协同实现,一个主goroutine,一个readLoop,一个writeLoop,后两个goroutine生命周期和连接一致。如果body没有被关闭,那么这次http事务就没有完成,会造成readLoop和 writeLoop 两个goroutine的阻塞,除非连接因超时终止了,否则相关资源无法被回收。

// 正确示例
func main() {
    resp, err := http.Get("<http://www.baidu.com>")

    // 关闭 resp.Body 的正确姿势
    if resp != nil {
        defer resp.Body.Close()
    }

    checkError(err)
    defer resp.Body.Close()

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

    fmt.Println(string(body))
}