Go网络错误处理需区分超时、临时性及永久性错误:通过net.Error接口的Timeout()和Temporary()方法判断,HTTP客户端须显式配置超时,重试应指数退避并设上限。

在 Go 中处理网络错误,关键在于区分不同类型的错误并针对性应对。标准库的 net 和 net/http 包返回的错误大多实现了 net.Error 接口,这让你能准确判断是连接拒绝、超时,还是其他临时性问题。
识别 net.Error 并检查超时与临时性
Go 的网络操作(如 http.Get、net.Dial)出错时,错误常为 net.OpError 类型,它嵌入了 net.Error 接口。你可以用类型断言提取,并调用 Timeout() 或 Temporary() 方法:
- Timeout() == true:说明操作超时(如 dial timeout、read timeout),通常可重试
- Temporary() == true:表示临时性故障(如连接被拒、无路由、资源不足),也适合重试
- Timeout() == false && Temporary() == false:多为永久性错误(如 DNS 解析失败、无效地址),一般不应重试
HTTP 客户端超时需显式配置
http.DefaultClient 默认不设超时,一次卡死会导致整个 goroutine 阻塞。务必自定义 http.Client 并设置 Timeout 或更精细的传输控制:
- 使用
http.Client{Timeout: 10 * time.Second}简单统一超时 - 更推荐用
http.Transport分别控制:DialContext控制建连时间,ResponseHeaderTimeout控制响应头到达时间,ReadTimeout控制完整响应读取时间 - 示例:
tr := &http.Transport{DialContext: (&net.Dialer{Timeout: 5 * time.Second}).DialContext}
区分常见底层错误码
某些错误底层会暴露系统级 errno(尤其在 Unix 系统),可通过 errors.Is 或类型断言配合 syscall.Errno 判断:
立即学习“go语言免费学习笔记(深入)”;
-
errors.Is(err, syscall.ECONNREFUSED):目标服务未监听(连接被拒) -
errors.Is(err, syscall.ENETUNREACH):网络不可达(如路由缺失) -
errors.Is(err, dns.ErrNoAnswer):DNS 查询无响应(需导入net/dns) - 注意:Windows 下对应错误码不同,跨平台建议优先依赖
net.Error接口方法而非具体 errno
重试逻辑应避免简单轮询
遇到临时或超时错误时重试是合理策略,但需加退避和上限:
- 用
time.Sleep配合指数退避(如 100ms → 200ms → 400ms)防止雪崩 - 限制最大重试次数(如 3 次),避免无限等待
- 对 HTTP 请求,可结合
context.WithTimeout或context.WithDeadline控制整体耗时 - 不要在
http.DefaultClient上直接重试——它不支持取消;始终使用带 context 的client.Do(req.WithContext(ctx))










