额度与限流
有两层限制,请分清:
1. 客户端限流(你的 key)
每个 key 默认 60 次/分钟。超出返回 429 rate_limited,并带 Retry-After 头(秒)。
2. 上游 CourtListener 额度(整个服务共享)
本服务使用 CourtListener 免费账户,上游额度很稀缺:
| 窗口 | 上游限额 | 本服务实际使用(留 10% 余量) |
|---|---|---|
| 每分钟 | 5 | 4 |
| 每小时 | 50 | 45 |
| 每日 | 125 | 112 |
这些额度由所有客户端共享,另有一部分后台日预算(默认 80 次/24 小时)专供自动同步和补全文。因此:
- 读取本地库的接口不耗额度:
/opinions/recent、/search(source=local,默认)、/courts、/govinfo/uscourts/recent(不带live)、已入库的/opinions/{id}。 - 可能耗额度的接口:见下表。响应体里的
quota_cost表示本次请求实际消耗的上游调用次数。
| 接口 | 消耗 |
|---|---|
GET /search?source=courtlistener |
1 次(结果缓存 30 分钟) |
POST /citations/verify |
1 次(缓存 24 小时) |
GET /dockets/{id} |
首次 1 次,之后永久缓存 |
GET /opinions/cl:{id}(本地没有时) |
最多 3 次(opinion、cluster、docket),之后入库;正文优先取法院 PDF,不耗额度 |
GET /govinfo/uscourts/recent?live=true |
0(走 GovInfo,不占 CourtListener) |
每个响应都带头 X-Upstream-Quota-Remaining:当前还能安全使用的上游调用数(取各窗口最小值)。GET /v1/quota 返回详细的窗口用量。
遇到 429 怎么办
{"error": {"code": "rate_limited", "message": "..."}}
- 读取
Retry-After头,等待相应秒数后重试(指数退避,加抖动)。 - 本服务对按需上游请求最多排队约 8 秒,仍无额度才返回 429。
- 优先改用本地接口(
source=local搜索、/opinions/recent);这些永不触发上游限额。 - 对同一篇判例避免重复请求,客户端侧缓存结果。
import time, httpx
def get(url, **kw):
for attempt in range(5):
r = httpx.get(url, **kw)
if r.status_code != 429:
return r
time.sleep(int(r.headers.get("Retry-After", 2 ** attempt)))
return r
async function get(url, opts, tries = 5) {
for (let i = 0; i < tries; i++) {
const r = await fetch(url, opts);
if (r.status !== 429) return r;
const wait = Number(r.headers.get("Retry-After") || 2 ** i);
await new Promise(res => setTimeout(res, wait * 1000));
}
throw new Error("still rate limited");
}