
在 go 中执行 http 请求时,必须先检查错误再 defer 关闭响应体;若未检查错误就直接 defer resp.body.close(),当请求失败导致 resp 为 nil 时,将触发 panic。
在 go 中执行 http 请求时,必须先检查错误再 defer 关闭响应体;若未检查错误就直接 defer resp.body.close(),当请求失败导致 resp 为 nil 时,将触发 panic。
在 Go 的 HTTP 客户端编程中,http.Get 的返回值包含两个部分:*http.Response 和 error。其语义约定非常明确:只要 err != nil,resp 必定为 nil。因此,任何对 resp(尤其是 resp.Body)的访问都必须以成功获取响应为前提。
正确的处理顺序是:
- 立即检查 err;
- 若出错,及时返回或处理,避免后续无效操作;
- 仅当 err == nil 时,才可安全调用 defer resp.Body.Close()。
✅ 正确示例:
resp, err := http.Get("https://www.google.com")
if err != nil {
log.Printf("HTTP request failed: %v", err)
return err // 或其他错误处理逻辑
}
defer resp.Body.Close() // 此时 resp 非 nil,Body 可安全关闭
// 后续读取响应体(如 io.ReadAll)
body, err := io.ReadAll(resp.Body)
if err != nil {
return err
}
fmt.Printf("Response length: %d", len(body))⚠️ 常见错误写法(会导致 panic):
resp, err := http.Get("https://invalid-url")
defer resp.Body.Close() // ❌ panic: runtime error: invalid memory address or nil pointer dereference
if err != nil {
return err
}该写法在 err != nil 时仍会执行 defer,而 resp 为 nil,调用 resp.Body.Close() 即崩溃。
? 补充说明:
- defer 语句在函数入口处注册,但实际执行在函数返回前;它不关心 resp 当前是否有效,只按注册顺序执行;
- http.Response.Body 是 io.ReadCloser,必须显式关闭以释放底层 TCP 连接(否则可能造成连接泄漏);
- 即使后续读取 body 失败(如 io.ReadAll 报错),resp.Body.Close() 仍需执行——而 defer 正好保证这一点,前提是它被安全注册。
总结:错误检查永远优先于资源清理的 defer 注册。这是 Go “显式错误处理”哲学的核心体现,也是保障程序健壮性的基本实践。

















