限流与幂等

限流保护服务稳定,幂等保证重试安全。资金类请求请始终携带 Idempotency-Key。

请求限流

项目值
限额每个 API Key 每分钟 120 次请求(可由部署方用 MERCHANT_RATE_LIMIT 调整)
超出时HTTP 429,code 为 RATE_LIMITED
计数范围按 Key 统计,与该 Key 下的接口、参数无关

建议为不同环境(测试 / 生产)创建不同的 Key,避免互相占用额度。

Idempotency-Key

资金类 POST 接口支持 Idempotency-Key 请求头。服务端会保存首次成功响应 24 小时:

场景行为
同键、同参数、首次成功正常执行并记录响应
同键、同参数、24 小时内重试直接重放原响应,并返回响应头 Idempotent-Replayed: true
同键、不同参数HTTP 422,IDEMPOTENCY_KEY_REUSED
同键、首次请求仍在处理中HTTP 409,IDEMPOTENCY_IN_PROGRESS
首次请求失败(非 2xx)不保存,可用同一个键安全重试

键的格式:8–255 位字母、数字或 - _ : .,推荐 UUID v4。校验时不会把 PIN、密码等敏感字段计入参数摘要。

reference 去重

POST /api/v1/payments 的 reference 是业务订单号:同一商户内,相同 reference 且金额一致时返回同一笔支付;金额不同返回 409 REFERENCE_CONFLICT。适合作为支付创建的业务幂等键。

重试示例

超时或 5xx 时,用同一个 Idempotency-Key 重试;4xx 不要重试。

import os
import time
import uuid
import requests

key = str(uuid.uuid4())
payload = {"amount": "12.34", "reference": "order-2026-0001"}
headers = {
    "Authorization": f"Bearer {os.environ['SPACEPAY_KEY']}",
    "Idempotency-Key": key,
}

for attempt in range(5):
    try:
        resp = requests.post(
            "https://your-domain/api/v1/payments",
            headers=headers, json=payload, timeout=15,
        )
    except requests.Timeout:
        time.sleep(2 ** attempt)
        continue

    if resp.status_code < 500 and resp.status_code != 429:
        resp.raise_for_status()
        break
    time.sleep(2 ** attempt)
else:
    raise RuntimeError("重试次数用尽")

有效期一览

对象有效期
支付单(checkout_url)30 分钟,过期后不能再支付
Idempotency-Key 记录24 小时
Webhook 重试最多 6 次,跨度约 8 小时
商户后台 API 请求日志最近 5 万条
i幂等键记录保存在数据库中,多实例共享;限流计数器按部署实例维护,多实例部署时建议在网关层统一限流。