同一笔支付回调来了三次,货发了两回,只加唯一索引算防住了吗?
同一笔支付回调来了三次,订单发了两回货,前端按钮置灰在这里帮不上忙——回调根本不走页面。按 2026 年项目交付习惯,防重的落点在后端:给一次业务意图一个唯一标识,把「这次处理过没有」和「写入数据」收进同一个原子动作,让重复请求拿到和第一次一致的结果。只加唯一索引能兜住一部分,但状态流转和结果回查缺了,客服和运维仍要人工收拾。
多出来的那一笔,通常不是用户点了两下
需要防的是同一个业务意图对应多条记录,而不是用户点了几次按钮。重复请求在日志里往往看不出差别:参数一样、时间接近,只是被处理了两遍。
按 2026 年常见交付经验,重复来源大致有几类:
- 客户端或网关超时自动重试,用户端只看到一次「提交中」;
- 用户刷新页面、返回再点,或 App 与小程序同时下单;
- 脚本绕过页面直接打接口,置灰对它没有约束;
- 消息与回调按至少一次投递,消费端没做去重就会再落一笔;
- 几百毫秒内的真实连点,这一类才是前端防抖能挡住的。
五类摆在一起,前端置灰覆盖的比例通常不高。前端防重属于体验优化,后端幂等才是数据正确性的底线,两者是叠加关系,不是二选一。
防重落在哪一层:幂等四件套的分工
判断一套防重能不能用,只看一件事:同一请求重复到达时,第二次的处理结果是否和第一次一致。围绕这个目标,交付时通常由四个组件配合,单独上任何一个都会漏。
- 幂等键:一次业务意图一个唯一标识,重发多少次都带同一个键。粒度要对齐业务,一次下单一个键,不要一次会话一个键;
- 唯一约束:把幂等键落到数据库唯一索引,让重复写入在存储层失败,而不是代码里先查再插;
- 状态机:业务对象从明确的初始状态流转,重复请求只做状态判断,不重新创建对象;
- 结果回查:重复请求返回首次处理结果,而不是抛一句「请勿重复提交」。
顺序的理由是:幂等键决定能否识别同一笔,唯一约束决定并发下靠谁兜底,状态机决定重复请求在哪一步停下,结果回查决定调用方看到什么。状态字段在 2026 年的常见做法是用数字配字典表,后续加枚举值时兼容成本更低。
几种常见做法分别能挡住什么
- 按钮置灰与防抖:挡真实连点,前端约半天到 1 人日可完成,对刷新、超时重试、脚本和回调重投无效;
- 一次性提交 token:进入表单先领、提交带回、服务端用掉即失效,能挡表单重复提交,对多端并发与回调重投覆盖有限,还需额外的存储和过期清理;
- 幂等键加唯一索引:覆盖超时重试、脚本刷接口、多端并发与回调重投,涉及接口契约和表结构,常见经验区间是 1~3 人日,代价是幂等记录要按周期清理;
- 分布式锁:适合保护同一资源的互斥改动,比如库存或余额。锁的持有时间要和业务耗时匹配,常见区间是几百毫秒到数秒,不匹配会出现锁提前释放或请求长期排队。
推进顺序上,前端置灰先做体验兜底;接口设计阶段就定下幂等键的传递位置;金额、库存、券这类敏感的写接口再补唯一索引与状态机;只有需要对同一资源互斥时才引入分布式锁。把分布式锁当成防重的通用方案,通常是投入产出比较低的一种选择。
交付现场:先上置灰、唯一索引排到下一期的那次返工
一次大促前的交付里,预算和排期都紧,客户要求先加按钮置灰顶一顶,后端唯一索引排到下一期。当时的约束是回调侧已接第三方,重投策略改不动;做法就只在前端做了防抖和置灰,回调入口仍按「先查订单状态、再更新发货」的写法。结果当晚第三方回调重投叠加客户端超时重试,券多发了若干张,第二天人工核对并逐一回滚,返工大约多花 1~2 人日,还占用了当天的排障时间。置灰不是不能上,而是不能只有它。
怎么验收:主动造重复请求
- 对同一个幂等键并发提交,常见做法是 10~50 次,结果应只落一条业务记录,且每次返回同一个业务单号;
- 人为制造超时重试与回调重投,核对最终记录数和业务状态与单次提交一致;
- 确认幂等记录的清理任务存在,不会无限增长。
反例也很明确:重复请求只返回「请勿重复提交」,不说清第一次是否成功;或者两次返回不同单号,调用方不知道该以哪条为准。把同一份请求重放多次,业务数据只有一份,各端看到的回答始终一致,这条口径能过,防重才算闭环。
适用与不适用边界
防重不是所有接口都要上,判断依据是重复一次会不会造成实际损失。
- 适合投入:下单、支付、退款、提现、领券、报名、跨系统回调处理;
- 可以简化:内部后台的低频操作,靠唯一索引兜底即可,不必上完整状态机与结果回查;
- 不必上:读接口、把状态设成固定值的自然幂等写操作、重复上报只做覆盖的统计埋点。
还有一条边界要写清楚:幂等解决的是同一笔业务意图重复到达,解决不了两笔不同意图的真实提交,也替代不了对账。对账仍需按日或按周期核对流水与业务记录,两者是互补关系,不能互相顶替。
常见问题
幂等键该由前端生成,还是后端下发更稳妥?
两者都能用。前端生成实现简单,适合自研客户端;后端下发多一次请求,但能覆盖刷新与多端并发,按业务风险取舍即可。
已经加了唯一索引,还需要额外配分布式锁吗?
通常不需要。唯一索引已能在并发下兜住重复写入;分布式锁更适合保护同一资源的互斥改动,比如库存扣减,两者职责不同。
幂等记录要保留多久,一直堆着会不会拖慢写入?
按业务对账周期对齐,常见经验区间是 1~7 天,到期由定时任务清理。保留期过长会让幂等表变成大表,影响写入效率。
两笔间隔很短的真实订单,会被幂等键误判成重复吗?
会,如果键的粒度太粗。键应按业务意图区分,一次下单一个键,而不是一个用户一个键或一次登录一个键。
下一步可以先梳理写接口清单,标出重复一次会产生损失的接口,再逐个确认幂等键由谁生成、落在哪张表的哪个唯一索引上、重复请求返回什么。周期紧的项目可先落置灰与唯一索引,状态机与结果回查放到后续迭代;业务本身低频、可人工兜底的场景,把核对流程写进交付文档也是合理选择。
-
系统程序开发,接口用同步还是异步?回调没配好线上就丢单
日期:2026年8月30日 阅读:98
-
系统程序开发,接口幂等放在哪一层才不容易出乱子?
日期:2026年8月22日 阅读:137
-
运营每周都要改活动开关,每次都找研发发版,配置该不该挪到配置中心?
日期:2026年10月14日 阅读:68
-
上线后 OPTIONS 预检一直 401,跨域头也加了,为啥浏览器还报跨域?
日期:2026年10月13日 阅读:102
-
列表翻页第二页又出现上一页最后一条,前端按主键去重就能先上线吗?
日期:2026年10月12日 阅读:49




