如何在Golang中处理网络请求错误_Golang网络异常处理思路

应优先用类型断言判断net.Error接口的Timeout()和Temporary()方法;http.Client.Timeout不控制DNS/TLS等前置阶段,需通过http.Transport细化超时;务必关闭resp.Body以防连接泄漏;重试需区分错误类型,避免对不可重试错误盲目重试。

判断 net.Error 类型比直接检查错误字符串更可靠

Go 的网络操作(如 http.Getnet.Dial)返回的错误多数实现了 net.Error 接口,它提供了 Timeout()Temporary() 方法。相比用 strings.Contains(err.Error(), "timeout") 这类脆弱匹配,应优先用类型断言:

if netErr, ok := err.(net.Error); ok {
    if netErr.Timeout() {
        // 处理超时,比如重试
    }
    if netErr.Temporary() {
        // 可能是临时性故障(如连接被拒、DNS 暂不可用)
    }
}

注意:Timeout() 返回 true 并不意味着一定是 context.DeadlineExceeded;而 context.DeadlineExceeded 是独立的错误值,需单独判断。

http.ClientTimeout 字段不控制 DNS 解析和 TLS 握手

http.

Client.Timeout 仅作用于整个请求生命周期(从发送开始到响应 body 读取完成),但 DNS 查询、TLS 握手、TCP 连接建立这些前置阶段不受其约束。常见表现是:设置 Timeout: 5 * time.Second,但遇到 DNS 故障时卡住 30 秒才报错。

  • 解决办法是用 http.Transport 分别控制各阶段:
  • DialContext 控制 TCP 连接(含 DNS 解析)
  • TLSHandshakeTimeout 控制 TLS 握手
  • ResponseHeaderTimeout 控制 header 返回时间

示例关键配置:

client := &http.Client{
    Timeout: 5 * time.Second,
    Transport: &http.Transport{
        DialContext: (&net.Dialer{
            Timeout:   3 * time.Second,
            KeepAlive: 30 * time.Second,
        }).DialContext,
        TLSHandshakeTimeout:   3 * time.Second,
        ResponseHeaderTimeout: 3 * time.Second,
    },
}

不要忽略 resp.Body.Close() 导致的连接泄漏和超时误判

即使请求失败(如 resp.StatusCode >= 400),只要 resp 非 nil,resp.Body 就一定存在且必须关闭。否则:

  • 底层 TCP 连接不会被复用,连接池快速耗尽
  • 后续请求可能因无可用连接而阻塞在 DialContext 阶段,表现为“假超时”
  • http.DefaultClient 默认复用连接,不关 body 会隐式拖慢整个客户端

正确写法始终包含 defer resp.Body.Close(),哪怕只读 status:

resp, err := client.Get("https://api.example.com")
if err != nil {
    return err
}
defer resp.Body.Close() // 即使下面要 return error,也必须先 close

if resp.StatusCode != http.StatusOK { return fmt.Errorf("bad status: %d", resp.StatusCode) }

重试逻辑里要区分可重试与不可重试错误

不是所有网络错误都适合重试。盲目重试 http.StatusForbiddennet.ErrClosed 只会放大问题。

  • 建议重试:net.OpError(连接拒绝、无路由)、context.DeadlineExceeded(非最终超时)、http.ErrUseLastResponse
  • 禁止重试:http.StatusUnauthorizedhttp.StatusForbiddenhttp.StatusNotFoundnet.ErrClosedurl.Error 中的 malformed URL
  • 谨慎重试:TLS 相关错误(如 x509.UnknownAuthorityError)通常不可修复,重试无意义

真正棘手的是中间状态——比如 TCP 连接成功但服务端进程崩溃,此时收到 RST 包,Go 报 read: connection reset by peer,这类错误是否重试,得结合业务语义判断。