你肯定遇过这种事:在咖啡店用APP点拿铁,点完支付,屏幕一直转圈圈,然后弹一句:网络不稳,支付失败,请重试。
你有点烦,但还是点了重试,这次成了,咖啡也拿到手。
你可能没察觉,你刚经历了软件里最常见的重试机制。要是做得够优雅,你连重试都不用点——APP后台悄悄多试几次,成了就直接过,真不行再告诉你。
今天就聊:请求失败(支付、发数据、调接口)时,怎么让系统靠谱地再试几次,还不把事情搞炸。

为啥要重试?因为世界本来就不稳
现在的系统,只要碰网络、调远程服务,失败是常态,不是意外。
•网抽风:Wi‑Fi弱一下、4G切5G、丢包
•服务忙:瞬间请求太多,拒一下,半秒就好
•资源占满:数据库连接池满了,等一毫秒就有空
•发布重启:服务滚动更新,几秒恢复
这些都是临时故障,不是彻底挂了。代码一失败就抛错给用户,体验烂到爆。悄悄重试一次,大部分问题就无声解决了。
重试的核心:用一点点自动等待,扛住瞬间不靠谱。
重试做得蠢,反而变灾难
别以为就是“失败再试10次”。乱重试会出大事:
1.火上浇油 对方已经过载,你还疯狂连刷10次,直接把服务打崩——重试风暴。
2.白费劲 有些错是永久的:参数错、权限过期、地址不对。重试一万次也没用,纯浪费资源。
3.重复扣款 最坑:第一次其实已经扣钱,只是响应超时,你重试一次,用户被扣两次。这就是幂等性问题。
所以重试不是“多试几次”,是有策略地试。
优雅重试三招:控节奏、认场景、保安全
1. 控节奏:别猛冲,要“退避”
失败别立刻重试,等一会儿,而且越往后等越久——指数退避。比如:
•第1次失败 → 等1秒
•第2次 → 等2秒
•第3次 → 等4秒
•第4次 → 等8秒
给对方恢复时间,也避免你变成攻击者。再加个随机抖动,防止一堆客户端同一时间重试撞车。
2. 认场景:只重试“能好的错”
分清楚两类错误:
可重试(临时):超时、5xx服务器错、连接断了、限流。
不可重试(永久):400参数错、401没权限、404找不到。重试没用,直接报错更省心。
代码里要明确:哪些异常能重试,哪些直接放弃。
3. 保安全:幂等性是底线
重试最危险的是重复执行。
幂等就是:执行1次和100次,结果一样。
•查询:安全,随便重试
•支付/扣款:不安全,重试要谨慎
解决办法:
•加唯一请求ID,服务端判重,只执行一次
•读操作自动重试,写操作谨慎重试,或让用户手动点
没幂等的重试,不是优雅,是危险。
优雅重试:用户完全无感
回到买咖啡:
你点支付,没报错、没卡死。后台悄悄重试2次,第二次成了。
你只看到支付成功,全程不知道出过问题。
开发者逻辑大概这样:
尝试次数 = 0
while 尝试次数 < 最大次数:
try:
调支付接口()
成功退出
catch 临时错误:
按次数算等待时间
等待
次数+1
catch 永久错误:
直接失败,不重试
再加一条:总超时。比如最多3次、不超30秒,别把请求挂死。
重试不是万能药,只是系统韧性一小步
重试只是“韧性工程”一小块,配合这些才稳:
•超时:别让慢请求拖死线程
•熔断:连续失败就先停一会儿,别硬冲
•降级:实在不行给友好提示,留手动重试入口
但重试是成本最低、见效最快的可靠手段。不用改架构,只在调接口时多问一句:这次失败,值得再给一次机会吗?
总结
以后写代码调远程接口,问自己三句:
1.这错是临时的还是永久的?
2.我重试会不会把对方打崩?
3.重试会不会重复执行、扣两次钱?
想清楚这三点,你就已经比大多数人更懂优雅重试。
好的重试,像个有分寸的服务员:不立刻走,也不死缠烂打,隔一会儿轻声问一次,真不行再安静离开。
就是这种安静又靠谱的“再试一次”,能让系统体验悄悄上好几个档次。
