接口重复提交:用幂等键处理回执丢失

请求已经被服务端处理,客户端却因为超时又发一次,会导致重复订单或重复操作。网络结果未知与业务处理失败不能直接画等号。

edyang · 2020-05-23

请求已经被服务端处理,客户端却因为超时又发一次,会导致重复订单或重复操作。网络结果未知与业务处理失败不能直接画等号。

幂等设计为同一业务意图提供稳定身份。服务端在持久化边界内记录幂等键和处理结果,重复请求返回已知结果;请求内容改变时不能仍复用同一个键。

接口重复提交:用幂等键处理回执丢失:处理路径与验证条件

一、问题的范围与前提

接口由请求身份、参数语义、授权条件和结果状态共同构成。HTTP 层成功只描述传输与响应,业务处理还可能处于受理、执行或等待确认阶段。将外部输入转换为内部对象以后,仍需核对类型、范围和当前状态,不能因为 JSON 能解析就直接使用。

二、技术分析与方案取舍

以创建记录为例,两个相同幂等键同时到达,应由持久化唯一约束或等效原子操作决定谁受理,而不是先查内存再各自插入。已受理状态与最终结果也要区分,重复请求不能在处理中得到假的完成响应。如果同一个键携带不同参数,返回冲突通常比复用旧结果更合理。

保留周期应覆盖实际重试窗口,设备动作还需要独立执行协议。

应用入口应有明确大小、时间和并发预算。正常和异常返回都遵循稳定结构,调用方可以据此选择等待、查询、修正或重试。涉及写入与外部动作时,为同一业务意图提供稳定身份,并在持久化边界内管理已受理结果,防止回执丢失造成重复执行。

三、实现与排查的顺序

  1. 确定业务意图的唯一范围。
  2. 在数据库建立唯一约束。
  3. 原子记录结果与关键状态。
  4. 重试前先查询未知结果。

按这个顺序保留中间结果,可以区分输入条件、处理过程和最终输出。前一阶段的条件不成立时,先解释对应错误,再继续后面的试验;单次返回成功不足以覆盖整条链路。

最小示例

1
2
业务意图 → 稳定幂等键 → 原子受理 → 保存结果
重复或未知:按相同身份查询已完成记录

示例关系要求身份与请求内容对应。内存去重无法覆盖进程重启,数据库唯一约束和结果记录需要处于明确边界;设备动作是否执行一次还需设备协议与任务状态配合。

四、验证和结果解释

至少关联请求到达、关键依赖调用和处理结果。日志记录标识与阶段即可,密码、Cookie、token 和原始敏感请求不应进入公共记录。排查时用同一入口比较请求与响应,再结合后端证据,避免页面统一错误文案掩盖具体原因。

需要验证的结果 保留的对照 不能由此推出的结论
同键并发只形成一条业务 固定输入与配置、对应输出 一次成功代表所有条件成功
回执丢失后可取回结果 中断前后状态与错误阶段 没有报错代表结果正确
不同参数误用同键会被拒绝 恢复后的同条件复测 临时恢复代表根因已经消失

验收除了正常返回,还包括重复提交、格式错误、依赖超时与调用方取消。系统应能对未知结果查询或恢复,而不是把每个超时都当成未执行。恢复范围尽量匹配故障,防止一个依赖异常引发所有服务同时反复重启。

五、适用边界与结论

内存去重在重启后失效,短 TTL 去重也可能早于客户端重试结束。涉及设备动作时,数据库幂等不自动保证物理执行只发生一次。

这条路径把“确定业务意图的唯一范围”与“重试前先查询未知结果”连在一起,中间保留可复查的条件。实施时优先确认“同键并发只形成一条业务”,再检查“不同参数误用同键会被拒绝”;两者都满足,才能在当前样本与配置范围内评价方案。设备、数据或软件版本改变以后,相关假设需要重新验证。

参考资料