前端请求重试应该如何设计?
简化版
请求重试适合临时网络错误、超时、部分 5xx,但不应无脑重试所有请求。设计时要考虑幂等性、最大次数、指数退避、抖动、取消机制和用户提示。非幂等操作如支付、下单要特别谨慎。
详细版
可重试场景:
- 网络短暂失败。
- 请求超时。
- 502、503、504。
- 429 在服务端允许时延迟重试。
不适合随意重试:
- 400 参数错误。
- 401/403 权限问题。
- 非幂等 POST。
- 支付、创建订单等敏感操作。
策略:
- 设置最大重试次数。
- 指数退避延迟。
- 加随机抖动避免同时重试。
- 支持取消。
- 记录重试日志。
完整版教学
一、为什么不能无脑重试
重试能提升弱网成功率,但也可能放大故障。如果服务器已经很忙,大量客户端同时重试,会让服务雪上加霜。
如果请求是非幂等的,重试还可能造成重复下单、重复扣款、重复提交。
二、幂等性是关键
幂等表示同一个操作执行一次和执行多次结果一致。GET 通常天然幂等,部分 PUT/DELETE 可以设计成幂等,POST 则不一定。
对于创建订单这类操作,服务端应提供幂等键。前端重试时带同一个幂等键,服务端保证只创建一次。
三、指数退避和抖动
指数退避是每次失败后等待更久再重试,例如 1s、2s、4s。
抖动是在延迟中加入随机值,避免大量客户端在同一时间再次请求,造成重试风暴。没有抖动时,客户端会按相同节拍重新同步,即使指数增长也可能周期性冲击服务端。
四、面试追问与工程落地
面试官可能问:“上传文件失败要怎么重试?”
小文件可以整体重试,大文件更适合分片上传和断点续传。每个分片可单独重试,最终服务端合并。这样失败成本更低。
工程中请求重试应该放在统一请求层,不要每个业务页面自己写一套。
五、退避算法与 Retry-After
固定 1 秒重试会让同一时刻失败的客户端再次同步撞击服务。第 n 次退避可先算上限,再用 full jitter 随机取值:
cap(n) = min(maxDelay, base × 2^n)
delay(n) = random(0, cap(n))
若 base=500ms、maxDelay=8000ms,第 0–4 次上限依次为 500、1000、2000、4000、8000ms;10000 个客户端会被随机摊开,而不是都在整秒同时请求。
| 结果 | 默认建议 | 原因 |
|---|---|---|
| 网络中断/超时 | 条件重试 | 可能是瞬态,但结果未知 |
| 429 | 尊重 Retry-After | 服务端明确限流 |
| 502/503/504 | 有界重试 | 网关/服务可能恢复 |
| 400/422 | 不重试 | 相同参数不会自愈 |
| 401/403 | 刷新身份或停止 | 权限问题不是瞬态 |
重试预算要包含“首次请求 + 重试次数 + 总耗时”;只限制次数,单次超时很长时仍会拖死用户。
六、幂等键和一次操作的身份
支付请求超时不代表支付失败,可能是服务器已扣款但响应丢失。客户端若生成新的订单请求重试,就会重复执行;正确方式是为一次业务意图生成稳定幂等键:
POST /orders
Idempotency-Key: 8f2c...same-for-all-retries
服务端原子记录 key、请求摘要和最终结果。相同 key + 相同请求返回原结果;相同 key + 不同参数应拒绝。幂等记录还要设置与业务重试窗口匹配的保留时间,例如允许 24 小时恢复就不能 5 分钟删除。
重试层必须支持 AbortSignal、总 deadline 和可观测日志,记录 attempt、等待时间、最终状态。前台请求通常重试 2–3 次已足够,后台任务可更久但应进入队列、熔断和告警体系。
当服务端已明确返回不可重试的业务错误时,应立即结束循环,避免把确定性失败变成额外负载。
七、常见误区与追问
- 误区:任何 5xx 都应该无限重试。 永久错误和过载会被放大,必须有次数、总时限和熔断。
- 误区:POST 天生不能重试。 它默认不幂等,但可通过稳定幂等键和服务端原子记录安全重试。
- 误区:请求超时就证明服务端没有执行。 响应可能丢失,操作状态未知,应查询或按同一幂等键重试。
- 追问:为什么指数退避还要 jitter? 避免大量客户端在相同指数时刻同步形成重试风暴。
- 追问:429 应等待多久? 优先解析服务端
Retry-After,并受客户端总 deadline 限制。 - 追问:PUT/DELETE 一定幂等吗? HTTP 语义期望幂等,但具体业务副作用和实现仍需验证。
- 追问:怎样避免重试拖慢用户? 设置单次超时、总 deadline、最大次数,并对非关键请求快速降级。
八、加强记忆
- 先分类:只重试瞬态、可恢复错误,不重试参数和权限错误。
- 再问幂等:读取通常安全,写操作需要稳定幂等键与服务端保证。
- 控制节奏:指数退避加随机抖动,429 尊重 Retry-After。
- 限制预算:最大次数、单次超时和总 deadline 同时存在。
- 支持取消:用户离开或新请求替代时停止等待与后续重试。
- 保持可观测:记录每次 attempt、延迟、结果和幂等键关联状态。