重复提交的写接口要怎么防重,幂等键放在请求头还是放在业务字段里

重复提交的写接口要怎么防重,取决于你要防的是哪一层。协议层的幂等描述的是「一次请求与多次相同请求对服务器的预期效果一致」,官方术语页把它写成 intended effect on the server 的一致性;业务层的重复提交还包含用户连点、任务重试、批次重放这些具体场景。幂等键放请求头还是放业务字段,答案也跟着分层。

协议层已经把方法分好类

方法 协议是否认定幂等 落到内容接口上的含义
GET、HEAD、OPTIONS、TRACE 幂等(属安全方法) 重复查询同一资源不改变状态
PUT 幂等 用同一份数据覆盖,重复执行结果一致
DELETE 幂等 首次可能返回 200,后续返回 404,效果不再叠加
POST 不保证幂等 新建类操作重复执行会产生多条记录
PATCH 不保证幂等 增量修改重复执行会累加

两个细节常被误读。其一是幂等不等于无副作用,术语页明确写了服务器仍可能记录每一次请求的到达时间;其二是每次响应可以不同,删除操作的返回码变化就是典型例子。所以「按幂等设计」管的是最终状态,不是响应字节完全一致。

追加类操作为什么要自己补

新建文章、导入归档这类接口多用提交语义,落在「不保证幂等」那一栏。客户端超时重试、队列重放、人工重复点击,都会把同一个意图变成多条记录。补法有两条路,作用面不同。

第一条是判重键。AnQiCMS 提供文档内容导入接口 /api/import/archive,同时支持按标题查询是否已存在,用于批量导入场景:调用方在写入前先查一次,命中就跳过或改为更新。这条路解决的是「同一条内容不要落两次」,它依赖内容自身的可辨识字段。

第二条是幂等键。给每一次业务意图生成一个不重复的编号,由服务端按这个编号记录处理结果,重复携带同一编号的请求直接返回上次结果。它解决的是「同一次动作不要执行两遍」,即使两次请求携带的数据略有差别,只要编号相同就按一次处理。

幂等键放请求头还是放业务字段

放请求头的好处是它与业务数据解耦:字段结构不变、重试时原样带上即可,服务端在中间层就能拦掉重复请求,网关与日志也便于按这个键统计。常见做法是用自定义头承载,并在接口文档里写清它的必填条件。

放业务字段的适合另一种场景:调用方是无法自定义请求头的客户端,或者这个键本身属于业务记录的一部分,需要随数据入库、随导出可查。ZIP 压缩包与 Excel 表格批量导入就是这类:批次号写在数据里,导入任务重放时按批次号回收结果。

取舍可以按三问定:调用方能不能稳定生成并携带这个键;键要不要随业务数据长期保存;服务端能否在写库前读到它。三问都能满足时放请求头更干净,任一问不满足就落到字段里。

接口文档要写清的边界

公开接口文档至少要把四件事说明白:这个接口是否接受幂等键、缺省时重复调用的后果、按标题查重与幂等键的优先关系,以及返回体如何区分「新建」「已存在被跳过」「重放返回旧结果」。

状态流转也要一并写清。AnQiCMS 的文档状态分为正式文档、草稿、待发布与回收站,导入接口带草稿标记时,重复调用造成的多余记录还会继续影响后续发布队列,这类返工比直接重复入库更难发现。API 调用示例里把参数含义标注完整,比在正文里补一句「请勿重复提交」有效。

常见问题

只有按标题查重够不够? 标题会变时不够。查重依赖内容字段,幂等键依赖意图;两者配合才能同时防住重复入库与重复执行。

幂等键要保存多久? 覆盖重试窗口即可,通常按任务最长执行时间与队列积压时间取较大值,并给出过期后的语义。

服务端怎么存这个键? 按键记录处理结果并设过期,注意同一键的并发冲突要显式处理,返回可辨识的重复提示,而不是笼统报失败。