proxy-pool/docs/api/distribution.md

201 lines
6.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Distribution API
## 1. 行为契约
Distribution API 只提供一次性独占提取:
```text
筛选 AVAILABLE
-> 锁定候选
-> 校验 Gateway 预留、TTL、健康与过滤条件
-> 原子 AVAILABLE -> EXTRACTED
-> 写 Extraction Record
-> 提交事务
-> 返回真实代理地址
```
事务提交前不得把地址写给 Client。返回成功后该 Proxy 不再参与 Gateway、
再次提取或可用库存统计。系统不跟踪 Client 是否使用、使用并发或何时停止,
也不提供 release、renew、status 或租约端点。
HTTP 契约源文件:`api/openapi/proxy-pool.yaml`。
## 2. 提取请求
```http
POST /api/v1/proxies/extract HTTP/1.1
Host: 127.0.0.1:8081
Content-Type: application/json
X-API-Key: TOKEN
X-Request-ID: req_01J4EXAMPLE
Idempotency-Key: extract-01J4EXAMPLE
```
PowerShell 调用示例:
```powershell
$body = @{
count = 5
fulfillment = "partial"
filters = @{ protocols = @("http"); regions = @("shanghai") }
} | ConvertTo-Json -Depth 4
Invoke-RestMethod `
-Method Post `
-Uri http://127.0.0.1:8081/api/v1/proxies/extract `
-Headers @{ "X-API-Key" = "TOKEN"; "Idempotency-Key" = "extract-SERIAL" } `
-ContentType application/json `
-Body $body
```
请求约束:
- `count` 至少为 1且不超过服务端 `maxCountPerRequest`
- `fulfillment` 省略时使用服务端配置,默认 `partial`
- 所有过滤数组执行“数组内 OR、不同维度 AND”。空数组等同不限制。
- `allowedUpstreams` 只能缩小 Client 可访问的 Upstream 集,不能扩大权限。
## 3. 成功响应
```json
{
"requestId": "req_01J4EXAMPLE",
"requested": 5,
"returned": 2,
"proxies": [
{
"id": "px_01J4A",
"protocol": "http",
"host": "192.0.2.10",
"port": 8080,
"username": "USER",
"password": "PASSWORD",
"url": "http://USER:PASSWORD@192.0.2.10:8080",
"region": "shanghai",
"carrier": "telecom",
"upstream": "provider-a",
"expiresAt": "2026-07-28T10:30:00Z",
"remainingTtlSeconds": 83,
"extractedAt": "2026-07-28T10:28:37Z"
}
]
}
```
`returned` 必须等于 `proxies` 数组长度。`partial` 模式中 `returned` 可以为
零;这仍表示请求语法有效,只是当前没有可提取库存。
返回的 `password``url` 含真实凭据。Client 必须限制日志、追踪和错误上报
对响应体的采集。服务端访问日志只记录数量、过滤摘要、Client、Upstream 和
Request ID不记录地址或凭据。
## 4. 数量语义
### 4.1 partial
锁定的符合条件数量少于 `count` 时,提交实际数量:
```text
requested=10, eligible=6, reserve=0 -> returned=6
```
### 4.2 allOrNothing
锁定数量不足时整个事务回滚:
```json
{
"type": "https://proxy-pool.local/problems/insufficient-proxies",
"title": "Insufficient proxies",
"status": 409,
"code": "INSUFFICIENT_PROXIES",
"detail": "requested 10 proxies but only 6 are currently eligible",
"requestId": "req_01J4EXAMPLE"
}
```
冲突响应后,之前被该请求临时锁定的 Proxy 仍为 AVAILABLE。
## 5. 资格过滤与 Gateway 预留
候选必须同时满足:
1. 权威状态是 AVAILABLE。
2. 没有 Worker 所有权,或已完成 Drain 且 Active/Reserved 均为零。
3. 剩余 TTL 不低于 `minRemainingTTL`
4. 最近健康检查不早于 `maxHealthCheckAge`
5. protocol、region、carrier、Upstream 满足过滤与 Client 权限。
6. 提取后符合条件的共享库存不低于 `reserveForGateway`
Worker-owned Proxy 不得直接提取。Controller 需要先发布 DRAINING等待 Worker
确认没有 Active/Reserved再清除所有权并进入提取事务。快照延迟时仍禁止
Gateway 与 Client 同时获得同一 Proxy。
## 6. 并发与事务
PostgreSQL Adapter 应在一个事务内使用 `FOR UPDATE SKIP LOCKED` 获取候选,
更新状态并写审计记录。所有状态更新必须包含 `state = 'AVAILABLE'` 前置条件。
关键不变量:
- 两个并发成功响应的 Proxy ID 集合交集为空。
- 状态更新或审计写入任一步失败,整个批次不返回。
- `allOrNothing` 不足时零行变为 EXTRACTED。
- PostgreSQL 不可写时返回 503不以内存结果冒充成功。
## 7. 幂等
提取是消耗库存的写操作。客户端收到超时后盲目重试可能再次提取一批不同
Proxy因此自动重试应提供稳定的 `Idempotency-Key`
服务端幂等记录至少包含Client ID、Key、请求体摘要、提交结果和过期时间。
同一 Client、同一 Key、相同摘要返回首次结果摘要不同返回 409。幂等记录和
Extraction Record 必须与状态更新处在相同事务边界或由同一权威恢复流程保证。
## 8. 认证、识别与限制
认证由部署配置决定OpenAPI 同时声明 API Key、Basic、Bearer 和无认证场景。
无认证并不关闭来源 CIDR、Client 识别和限流:
- 直连请求使用来源 IP 形成匿名 Client。
- 只有来源属于 `trustedProxies` 时才接受转发头。
- 全局和每 Client 限流在查询库存前执行。
- 过滤条件、数量、请求体和 Header 都有长度/数量上限。
## 9. 错误模型
所有非 2xx 响应使用 `application/problem+json`
- `400`JSON、Header 或基本格式无效。
- `401`:认证失败。
- `403`:来源控制、权限或 Upstream 访问被拒绝。
- `409`allOrNothing 库存不足,或幂等 Key 冲突。
- `422`:数量、枚举或过滤组合违反业务约束。
- `429`:全局或 Client 速率限制,响应 `Retry-After`
- `503`PostgreSQL 不可写、服务排空或权威状态不可用。
错误响应不得包含 Provider Secret、Proxy 凭据、SQL 或内部拓扑。
## 10. 审计记录
每个被提交的 Proxy 对应一条 Extraction Record
```text
proxyId, clientId, sourceIP, requestId, upstream, extractedAt, expiresAt
```
无认证时 `clientId` 使用 `anonymous` 或稳定匿名标识并保留 `sourceIP`。记录只
用于审计、排错和计费事实不承担资源归还语义。Proxy 到期后可以清理运行
记录,但 Extraction Record 按审计保留策略归档。