跳转到主内容
极星编程网:以代码为星,赴技术山海!

Go语言重试如何封装_Go语言错误重试操作教程【必看】

Go标准库不提供HTTP重试机制,必须手动封装;推荐用github.com/cenkalti/backoff/v4实现可控重试,需注意错误分类、req.Clone、上下文取消及body可重放性。 重试逻辑必须自己写,标准库不提供 Go 的
net/http
和
context
包里没有
Retry
、
DoWithRetry
或任何自动重试函数。你看到的“重试生效”,大概率是服务端 302 重定向、代理层行为,或是别人已经封装好的工具。别信“设了
Client.Timeout
就会重试”这种说法——它只控制单次请求超时,失败后直接返回错误,绝不会多发一次。 用
backoff.Retry
封装最省心,但得配对用对参数 社区事实标准是
github.com/cenkalti/backoff/v4
,它把退避策略、上下文取消、最大重试次数都收口了。手写 for+time.Sleep 容易漏掉 jitter、忽略
ctx.Done()
、共享退避状态错乱,还可能阻塞 goroutine。
backoff.NewExponentialBackOff()
默认
InitialInterval=100ms
、
MaxElapsedTime=10s
,但没开 jitter,也没显式设最大重试次数,线上慎用 必须包一层
backoff.WithJitter(bo)
,否则多个请求在相同时间点重试,容易触发下游雪崩 必须用
backoff.WithContext(bo, ctx)
,否则重试过程完全无视 cancel 或 timeout 错误分类要前置:网络类(
net.OpError
、
context.DeadlineExceeded
)、5xx/429 响应可重试;400/401/404 等业务错误必须用
backoff.Permanent(err)
拦住
req.Clone(ctx)
不是可选项,是必做项 HTTP 请求重试失败最常见的原因是 body 不可重放。
req.Body
是一次性读取流,第一次
Do()
后就关闭或 EOF。下次再用原
*http.Request
,会报
http: Request.Body is nil
或
http: read on closed response body
。 go语言参考手册 中文CHM版 Go 是一个开源的编程语言,它能让构造简单、可靠且高效的软件变得容易。本文给大家带来Go参考手册,需要的可以来下载! Go是从2007年末由Robert Griesemer, Rob Pike, Ken Thompson主持开发,后来还加入了Ian Lance Taylor, Russ Cox等人,并最终于2009年11月开源,在2012年早些时候发布了Go 1稳定版本。现在Go的开发已经是完全开放的,并且拥有一个活跃的社区。 Go 语言特色 简洁、快速、安全 并行、有趣、开源 内存管理、v数组安全、编译 下载 每次重试前必须调
req.Clone(ctx)
,生成新请求实例 如果原始
req.Body
是
strings.NewReader
或
bytes.NewReader
,克隆后可用;但
os.Stdin
、文件句柄、管道等不可克隆,得提前缓存成 bytes 别试图复用
req.Header
map——虽然它能共享,但修改它会影响所有克隆请求,容易串扰 封装成
RetryClient
时,别暴露底层
http.Client
结构体封装比函数更利于配置统一和复用,但字段设计很关键。导出一个可被外部随意改的
http.Client
字段,等于把重试语义全交出去了——别人改了
Timeout
或
Transport
,你的重试间隔、错误判断就全失效。 立即学习 “ go语言免费学习笔记(深入) ”; 只暴露
Do(req *http.Request) (*http.Response, error)
方法 把
MaxRetries
、
BackOff
、
ShouldRetry
(错误判断函数)设为私有字段,初始化时锁定 不同接口需要差异化重试策略?别共用一个全局 client,按需 new
RetryClient
实例 上传类请求(如大文件 POST)默认不该重试 500,因为服务端可能已接收部分数据;查询类可以重试,这个差异必须由调用方传参或实例化时决定 真正难的不是“怎么让请求多发几次”,而是判断“这次失败是不是值得再试一次”,以及“下一次该隔多久再试”。这两个问题没想清楚,加再多层封装也只是把错误放大得更隐蔽。

相关文章