错误码与频率限制
HTTP 状态码
| 状态码 | 含义 | 怎么处理 |
|---|---|---|
200 | 请求已处理 | 仍需检查 ok 字段 |
400 | 参数错误 | 按 message 修正入参,重试无用 |
401 | 密钥无效 / 缺失,或账号已停用 | 见认证 |
403 | 无权限,或引用了不属于你的资源 | 确认资源归属;部分功能需要对应套餐 |
404 | 资源不存在,或不属于你 | 两种情况返回相同,核对 ID |
429 | 请求过于频繁 | 退避后重试,见下 |
5xx | 服务端异常 | 退避重试;持续出现请提工单 |
为什么「不存在」和「不属于你」返回一样? 这是刻意的。如果两者可区分,任何人都能靠遍历 ID 探出系统里存在哪些资源 —— 那本身就是一种信息泄露。
该重试和不该重试
| 状态码 | 重试 | 说明 |
|---|---|---|
429 502 503 504 | ✅ 指数退避 | 临时状况 |
500 | ⚠️ 最多一两次 | 可能是稳定复现的服务端问题 |
400 401 403 404 | ❌ 不要重试 | 重试多少次结果都一样,只会更快触发限流 |
频率限制
接口有全局频率限制,超限返回 429。建议:
- 用指数退避(1s → 2s → 4s → 8s),不要固定间隔硬重试。
- 批量场景优先用列表接口一次取回,而不是循环调详情接口。
- 统计类数据按分钟粒度聚合,轮询快于 1 分钟没有意义。
import time, requests
def call_with_retry(method, path, tries=5, **kw):
delay = 1
for i in range(tries):
r = S.request(method, BASE + path, timeout=20, **kw)
if r.status_code in (429, 502, 503, 504) and i < tries - 1:
time.sleep(delay)
delay *= 2 # 指数退避
continue
d = r.json()
if not d.get("ok"):
raise RuntimeError(f"{path}: {d.get('message')} (HTTP {r.status_code})")
return d
raise RuntimeError(f"{path}: 重试 {tries} 次仍失败")