Go标准库不提供HTTP重试机制,必须手动封装;推荐用github.com/cenkalti/backoff/v4实现可控重试,需注意错误分类、req.Clone、上下文取消及body可重放性。
重试逻辑必须自己写,标准库不提供
Go 的
和
包里没有
、
或任何自动重试函数。你看到的“重试生效”,大概率是服务端 302 重定向、代理层行为,或是别人已经封装好的工具。别信“设了
就会重试”这种说法——它只控制单次请求超时,失败后直接返回错误,绝不会多发一次。
用
封装最省心,但得配对用对参数
社区事实标准是
,它把退避策略、上下文取消、最大重试次数都收口了。手写 for+time.Sleep 容易漏掉 jitter、忽略
、共享退避状态错乱,还可能阻塞 goroutine。
默认
、
,但没开 jitter,也没显式设最大重试次数,线上慎用
必须包一层
,否则多个请求在相同时间点重试,容易触发下游雪崩
必须用
,否则重试过程完全无视 cancel 或 timeout
错误分类要前置:网络类(
、
)、5xx/429 响应可重试;400/401/404 等业务错误必须用
拦住
不是可选项,是必做项
HTTP 请求重试失败最常见的原因是 body 不可重放。
是一次性读取流,第一次
后就关闭或 EOF。下次再用原
,会报
或
。
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数组安全、编译
下载
每次重试前必须调
,生成新请求实例
如果原始
是
或
,克隆后可用;但
、文件句柄、管道等不可克隆,得提前缓存成 bytes
别试图复用
map——虽然它能共享,但修改它会影响所有克隆请求,容易串扰
封装成
时,别暴露底层
结构体封装比函数更利于配置统一和复用,但字段设计很关键。导出一个可被外部随意改的
字段,等于把重试语义全交出去了——别人改了
或
,你的重试间隔、错误判断就全失效。
立即学习
“
go语言免费学习笔记(深入)
”;
只暴露
方法
把
、
、
(错误判断函数)设为私有字段,初始化时锁定
不同接口需要差异化重试策略?别共用一个全局 client,按需 new
实例
上传类请求(如大文件 POST)默认不该重试 500,因为服务端可能已接收部分数据;查询类可以重试,这个差异必须由调用方传参或实例化时决定
真正难的不是“怎么让请求多发几次”,而是判断“这次失败是不是值得再试一次”,以及“下一次该隔多久再试”。这两个问题没想清楚,加再多层封装也只是把错误放大得更隐蔽。
net/httpcontextRetryDoWithRetryClient.Timeoutbackoff.Retrygithub.com/cenkalti/backoff/v4ctx.Done()backoff.NewExponentialBackOff()InitialInterval=100msMaxElapsedTime=10sbackoff.WithJitter(bo)backoff.WithContext(bo, ctx)net.OpErrorcontext.DeadlineExceededbackoff.Permanent(err)req.Clone(ctx)req.BodyDo()*http.Requesthttp: Request.Body is nilhttp: read on closed response bodyreq.Clone(ctx)req.Bodystrings.NewReaderbytes.NewReaderos.Stdinreq.HeaderRetryClienthttp.Clienthttp.ClientTimeoutTransportDo(req *http.Request) (*http.Response, error)MaxRetriesBackOffShouldRetryRetryClient