بنقرة واحدة
idempotency-retry
设计幂等接口和重试策略时使用。适用于支付、扣减、订单、关键写操作。优先使用 Idempotency-Key + 业务去重键 + 并发冲突处理(ETag/版本号)。
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
设计幂等接口和重试策略时使用。适用于支付、扣减、订单、关键写操作。优先使用 Idempotency-Key + 业务去重键 + 并发冲突处理(ETag/版本号)。
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
设计 API 认证鉴权和权限矩阵时使用。适用于多角色系统、租户隔离、字段级权限。优先使用 OAuth 2.0 / JWT + RBAC + 资源归属检查。
设计具体 API 端点时使用。适用于资源建模后的下一步、列端点清单、HTTP 方法和状态码选择。优先使用 RFC 7231 HTTP 语义 + GitHub REST 命名规范。
设计 API 错误码和错误结构时使用。适用于错误响应规范、调用方错误处理、调试可观测。优先使用 RFC 7807 Problem Details + 业务错误码 + 调用方处理建议。
输出 OpenAPI 契约和 Mock 服务时使用。适用于 API 设计的最后一步、给前端/后端/QA 的交付。优先使用 OpenAPI 3.1 + Mock 数据覆盖所有路径 + 详细的下游交接清单。
设计列表接口的分页、筛选、排序、搜索时使用。适用于所有列表 API。优先使用 cursor 分页(大数据)或 offset 分页(小数据)+ 统一筛选/排序规范。
设计请求和响应结构时使用。适用于字段定义、校验规则、响应格式。优先使用 JSON:API 风格 + 字段稳定性 + 完整校验规则。
| name | idempotency-retry |
| description | 设计幂等接口和重试策略时使用。适用于支付、扣减、订单、关键写操作。优先使用 Idempotency-Key + 业务去重键 + 并发冲突处理(ETag/版本号)。 |
参考来源:Stripe Idempotency、GitHub API Conditional Requests
问题:网络不可靠,客户端重试会重复创建/扣款
例:
1. 客户端 POST /charge 扣款 100 元
2. 服务端处理成功,返回响应中
3. 网络中断,客户端没收到响应
4. 客户端重试 POST /charge → 又扣 100 元
5. 用户被扣 200 元 ❌
幂等:多次执行相同请求,结果一致
天然幂等:
- GET(查询)
- PUT(完全替换,结果一致)
- DELETE(删除一次后再删返回 404 或 204)
非幂等:
- POST(每次创建新资源)
- PATCH(部分更新,多次执行可能不同)
需要设计幂等的:
- POST 创建(订单、支付、扣减)
- 触发动作(POST /orders/{id}/refund)
请求:
POST /charges
Idempotency-Key: <uuid-generated-by-client>
服务端逻辑:
1. 收到请求,提取 Idempotency-Key
2. 检查 (Idempotency-Key, endpoint) 是否已处理过
- 已处理 → 返回上次的响应(不再执行)
- 未处理 → 处理 + 存储 (key, response)
3. 重复请求都返回同一响应
存储期限:通常 24 小时
客户端责任:
- 每个独立操作生成唯一 Key
- 重试时复用同一 Key(关键!)
- Key 通常用 UUID v4
某些场景天然有业务去重键:
订单去重:
POST /orders
Body: { "user_id": "usr_1", "external_order_id": "shop_order_123" }
服务端用 (user_id, external_order_id) 去重
支付去重:
POST /payments
Body: { "order_id": "ord_1", "amount": 100 }
服务端用 (order_id) 去重(一个订单只能支付一次)
优点:业务规则天然防重
缺点:需要业务字段支持
读取资源:
GET /users/{id}
→ Header: ETag: "v123"
→ Body: { ... }
更新资源:
PATCH /users/{id}
Header: If-Match: "v123"
Body: { "name": "新名字" }
服务端逻辑:
- 检查 ETag 是否匹配当前版本
- 不匹配 → 409 Conflict
- 匹配 → 更新 + 生成新 ETag
错误响应:
HTTP 409 Conflict
{
"code": "version_conflict",
"message": "Resource has been modified by another request",
"current_etag": "v124"
}
请求:
PATCH /users/{id}
Body: {
"name": "新名字",
"version": 5
}
服务端:
UPDATE users SET name = ?, version = version + 1
WHERE id = ? AND version = 5
如果影响行数 = 0 → 冲突 → 返回 409
适用:竞争激烈的资源
实现:
- Redis 锁(SET NX EX)
- 数据库行锁(SELECT FOR UPDATE)
API 层:
- 通常不暴露锁
- 内部实现处理
什么情况可以重试:
✅ 网络错误(连接超时、断开)
✅ 5xx 错误
✅ 429 Too Many Requests(按 Retry-After)
什么情况不可以重试:
❌ 4xx(客户端错误,重试也是错的)
❌ 业务错误(如余额不足)
指数退避:
第 1 次失败:等待 1s
第 2 次失败:等待 2s
第 3 次失败:等待 4s
第 N 次失败:等待 min(2^N, max_delay)
+ 抖动(避免雪崩):等待 ± 30% 随机
最大重试次数:3~5 次
HTTP 429 Too Many Requests
Retry-After: 60 ← 秒数
或:
Retry-After: Wed, 21 Oct 2026 07:28:00 GMT ← HTTP-date
HTTP 503 Service Unavailable
Retry-After: 120
客户端必须遵循 Retry-After
Rate Limit Headers(GitHub 风格):
X-RateLimit-Limit: 100 ← 限制
X-RateLimit-Remaining: 75 ← 剩余
X-RateLimit-Reset: 1611331200 ← 重置时间(Unix)
X-RateLimit-Reset-After: 60 ← 多少秒后重置
或自定义:
Retry-After: 60
## 支付接口幂等设计
### 接口
POST /payments
### 请求
Headers:
Idempotency-Key: <uuid> ← 必须
Body:
{
"order_id": "ord_123",
"amount": 9999,
"currency": "CNY",
"method": "wechat"
}
### 双重防护
1. Idempotency-Key(客户端层)
2. order_id 去重(业务层)
### 服务端逻辑
1. 提取 Idempotency-Key
2. 检查 redis:key=idem:<key>:payments
- 存在 → 返回缓存响应
- 不存在 → 继续
3. 检查业务去重:order_id 是否已支付
- 已支付 → 返回已存在的支付记录
- 未支付 → 继续
4. 处理支付
5. 缓存响应(24h)+ 返回
### 错误响应
HTTP 409 Conflict
{
"code": "duplicate_payment",
"message": "Payment for this order already exists",
"existing_payment_id": "pay_xxx"
}
### 客户端重试
- 网络错误:相同 Idempotency-Key 重试
- 5xx:相同 Idempotency-Key 重试
- 200/201:完成
- 4xx:不重试
- 409 duplicate_payment:使用 existing_payment_id
1. 识别需要幂等的端点
- 创建:POST /resources
- 触发动作:POST /resources/{id}/action
- 涉及金额/扣减/审批的操作
2. 选择幂等机制
- Idempotency-Key(通用)
- 业务去重键(如有自然 ID)
3. 识别需要并发控制的端点
- 多人编辑同一资源
- 库存扣减
4. 选择并发机制
- ETag / If-Match
- version 字段
- 锁
5. 设计重试策略
- Retry-After
- Rate Limit Headers
- 客户端指数退避建议
6. 写入文档:
- 哪些端点支持 Idempotency-Key
- 哪些必须传 Idempotency-Key
- 重试策略
- 限流策略
□ POST 创建/扣减接口是否有幂等设计
□ Idempotency-Key 是否必填还是可选
□ 服务端是否真的实现了幂等存储
□ 是否同时有业务去重键(双重防护)
□ 并发冲突是否有处理(ETag / version)
□ 限流是否返回 Retry-After
□ Rate Limit Headers 是否完整
□ 文档是否说明哪些错误可重试
templates/idempotency-retry-template.md — 幂等设计 + 重试策略 + 限流规范模板上游:
endpoint-design → 标注哪些端点需要幂等
平行:
error-handling → 409 Conflict / 429 错误码
request-response → Idempotency-Key Header
下游:
openapi-mock → OpenAPI 中标注幂等
转交后端 → 实现幂等存储和并发控制