服务端与数据 / 进阶

接口幂等:网络重试不应该创建两笔订单

客户端超时后重试是正常行为。对支付、下单等写接口,引入幂等键并在数据库事务中认领请求,才能避免重复副作用。

超时不代表服务端没有执行

客户端在 2 秒后超时,但服务端可能已经提交订单,只是响应丢失。此时再次 POST 会生成第二笔订单。幂等的目标不是禁止重试,而是让同一个业务意图的多次提交得到同一个结果。

保存请求指纹和最终响应

同一个用户和 key 只能插入一次。request_hash 用于阻止客户端误用同一个 key 提交不同参数;完成后保存状态码和响应体,后续重试直接返回快照。

EXAMPLE / 02Idempotency
CREATE TABLE idempotency_keys (
  user_id bigint NOT NULL,
  key text NOT NULL,
  request_hash text NOT NULL,
  status text NOT NULL CHECK (status IN ('processing', 'completed')),
  response_status int,
  response_body jsonb,
  expires_at timestamptz NOT NULL,
  PRIMARY KEY (user_id, key)
);

在事务里认领请求

读取 Idempotency-Key,并校验格式和长度;在事务中插入 processing 记录;唯一冲突时读取已有记录;如果 request_hash 不同,返回 409;如果已 completed,原样返回响应快照;只有认领成功的请求执行业务写入,并把幂等记录更新为 completed。

锁过期、进程崩溃或 Redis 故障都可能让业务数据和幂等状态分离。最终防线应是与业务写入同库的唯一约束和事务。