352 lines
9.8 KiB
YAML
352 lines
9.8 KiB
YAML
openapi: 3.1.0
|
||
info:
|
||
title: Proxy Pool HTTP API
|
||
version: 1.0.0
|
||
description: |
|
||
Distribution API performs one-time exclusive extraction. A successful
|
||
operation atomically transitions every returned proxy from AVAILABLE to
|
||
EXTRACTED. Extracted proxies are never allocated again and there is no
|
||
release, renew, or lease API.
|
||
servers:
|
||
- url: http://127.0.0.1:8081
|
||
description: Distribution API
|
||
tags:
|
||
- name: Distribution
|
||
- name: Health
|
||
paths:
|
||
/api/v1/proxies/extract:
|
||
post:
|
||
tags: [Distribution]
|
||
operationId: extractProxies
|
||
summary: 一次性独占提取代理
|
||
description: |
|
||
服务端先完成筛选、行锁定、AVAILABLE -> EXTRACTED 状态更新和审计记录
|
||
写入,再返回代理。相同代理不会返回给两个成功请求。
|
||
|
||
`partial` 允许实际返回数量小于请求数量;`allOrNothing` 数量不足时不
|
||
提取任何代理并返回 409。未传 `fulfillment` 时使用服务端配置,默认
|
||
为 `partial`。`Idempotency-Key` 可避免客户端因响应丢失重试而再次消耗
|
||
库存。
|
||
security:
|
||
- ApiKeyAuth: []
|
||
- BasicAuth: []
|
||
- BearerAuth: []
|
||
- {}
|
||
parameters:
|
||
- $ref: '#/components/parameters/RequestID'
|
||
- $ref: '#/components/parameters/IdempotencyKey'
|
||
requestBody:
|
||
required: true
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ExtractRequest'
|
||
examples:
|
||
partial:
|
||
value:
|
||
count: 5
|
||
fulfillment: partial
|
||
filters:
|
||
protocols: [http]
|
||
regions: [shanghai]
|
||
allOrNothing:
|
||
value:
|
||
count: 10
|
||
fulfillment: allOrNothing
|
||
filters:
|
||
allowedUpstreams: [provider-a, provider-b]
|
||
responses:
|
||
'200':
|
||
description: 提取事务已提交;返回的代理已永久退出可分配池
|
||
headers:
|
||
X-Request-ID:
|
||
$ref: '#/components/headers/RequestID'
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/ExtractResponse'
|
||
'400':
|
||
$ref: '#/components/responses/BadRequest'
|
||
'401':
|
||
$ref: '#/components/responses/Unauthorized'
|
||
'403':
|
||
$ref: '#/components/responses/Forbidden'
|
||
'409':
|
||
description: allOrNothing 模式下符合条件的库存不足,未提取任何代理
|
||
content:
|
||
application/problem+json:
|
||
schema:
|
||
$ref: '#/components/schemas/Problem'
|
||
example:
|
||
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
|
||
'422':
|
||
$ref: '#/components/responses/UnprocessableEntity'
|
||
'429':
|
||
$ref: '#/components/responses/TooManyRequests'
|
||
'503':
|
||
$ref: '#/components/responses/ServiceUnavailable'
|
||
/health/live:
|
||
get:
|
||
tags: [Health]
|
||
operationId: getLiveness
|
||
summary: 进程存活探针
|
||
security: []
|
||
responses:
|
||
'200':
|
||
description: 进程存活
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/Health'
|
||
/health/ready:
|
||
get:
|
||
tags: [Health]
|
||
operationId: getReadiness
|
||
summary: Distribution 就绪探针
|
||
description: PostgreSQL 不可用或权威状态不可写时返回 503。
|
||
security: []
|
||
responses:
|
||
'200':
|
||
description: 可接受提取请求
|
||
content:
|
||
application/json:
|
||
schema:
|
||
$ref: '#/components/schemas/Health'
|
||
'503':
|
||
$ref: '#/components/responses/ServiceUnavailable'
|
||
components:
|
||
securitySchemes:
|
||
ApiKeyAuth:
|
||
type: apiKey
|
||
in: header
|
||
name: X-API-Key
|
||
BasicAuth:
|
||
type: http
|
||
scheme: basic
|
||
BearerAuth:
|
||
type: http
|
||
scheme: bearer
|
||
parameters:
|
||
RequestID:
|
||
name: X-Request-ID
|
||
in: header
|
||
required: false
|
||
description: 调用方请求标识;缺省时由服务端生成。
|
||
schema:
|
||
type: string
|
||
maxLength: 128
|
||
IdempotencyKey:
|
||
name: Idempotency-Key
|
||
in: header
|
||
required: false
|
||
description: |
|
||
同一客户端在幂等记录保留期内重用该键会得到首次提交结果,不会再次
|
||
提取。建议所有会自动重试的客户端提供。
|
||
schema:
|
||
type: string
|
||
minLength: 8
|
||
maxLength: 128
|
||
headers:
|
||
RequestID:
|
||
description: 服务端最终使用的请求标识。
|
||
schema:
|
||
type: string
|
||
schemas:
|
||
ExtractRequest:
|
||
type: object
|
||
additionalProperties: false
|
||
required: [count]
|
||
properties:
|
||
count:
|
||
type: integer
|
||
minimum: 1
|
||
maximum: 1000
|
||
description: 仍受服务端 maxCountPerRequest 限制。
|
||
fulfillment:
|
||
type: string
|
||
enum: [partial, allOrNothing]
|
||
description: 缺省时使用服务端配置;默认 partial。
|
||
filters:
|
||
$ref: '#/components/schemas/ExtractFilters'
|
||
ExtractFilters:
|
||
type: object
|
||
additionalProperties: false
|
||
properties:
|
||
protocols:
|
||
type: array
|
||
uniqueItems: true
|
||
items:
|
||
type: string
|
||
enum: [http, https, socks5]
|
||
regions:
|
||
type: array
|
||
uniqueItems: true
|
||
items:
|
||
type: string
|
||
carriers:
|
||
type: array
|
||
uniqueItems: true
|
||
items:
|
||
type: string
|
||
allowedUpstreams:
|
||
type: array
|
||
uniqueItems: true
|
||
items:
|
||
type: string
|
||
ExtractResponse:
|
||
type: object
|
||
additionalProperties: false
|
||
required: [requestId, requested, returned, proxies]
|
||
properties:
|
||
requestId:
|
||
type: string
|
||
requested:
|
||
type: integer
|
||
minimum: 1
|
||
returned:
|
||
type: integer
|
||
minimum: 0
|
||
proxies:
|
||
type: array
|
||
items:
|
||
$ref: '#/components/schemas/ExtractedProxy'
|
||
ExtractedProxy:
|
||
type: object
|
||
additionalProperties: false
|
||
required:
|
||
- id
|
||
- protocol
|
||
- host
|
||
- port
|
||
- url
|
||
- upstream
|
||
- expiresAt
|
||
- remainingTtlSeconds
|
||
- extractedAt
|
||
properties:
|
||
id:
|
||
type: string
|
||
example: px_01J4EXAMPLE
|
||
protocol:
|
||
type: string
|
||
enum: [http, https, socks5]
|
||
host:
|
||
type: string
|
||
example: 192.0.2.10
|
||
port:
|
||
type: integer
|
||
minimum: 1
|
||
maximum: 65535
|
||
username:
|
||
type: string
|
||
password:
|
||
type: string
|
||
format: password
|
||
description: 真实代理凭据,只出现在提取成功响应中。
|
||
url:
|
||
type: string
|
||
format: uri
|
||
description: 含真实代理凭据的连接 URL,必须按敏感数据处理。
|
||
example: http://USER:PASSWORD@192.0.2.10:8080
|
||
region:
|
||
type: string
|
||
carrier:
|
||
type: string
|
||
upstream:
|
||
type: string
|
||
expiresAt:
|
||
type: string
|
||
format: date-time
|
||
remainingTtlSeconds:
|
||
type: integer
|
||
minimum: 0
|
||
extractedAt:
|
||
type: string
|
||
format: date-time
|
||
Health:
|
||
type: object
|
||
additionalProperties: false
|
||
required: [status]
|
||
properties:
|
||
status:
|
||
type: string
|
||
enum: [ok, degraded]
|
||
version:
|
||
type: string
|
||
configVersion:
|
||
type: string
|
||
Problem:
|
||
type: object
|
||
additionalProperties: true
|
||
required: [type, title, status, code]
|
||
properties:
|
||
type:
|
||
type: string
|
||
format: uri
|
||
title:
|
||
type: string
|
||
status:
|
||
type: integer
|
||
code:
|
||
type: string
|
||
detail:
|
||
type: string
|
||
requestId:
|
||
type: string
|
||
invalidParams:
|
||
type: array
|
||
items:
|
||
type: object
|
||
required: [name, reason]
|
||
properties:
|
||
name:
|
||
type: string
|
||
reason:
|
||
type: string
|
||
responses:
|
||
BadRequest:
|
||
description: 请求体、Header 或 JSON 格式无效
|
||
content:
|
||
application/problem+json:
|
||
schema:
|
||
$ref: '#/components/schemas/Problem'
|
||
Unauthorized:
|
||
description: 所配置的认证方法未通过
|
||
content:
|
||
application/problem+json:
|
||
schema:
|
||
$ref: '#/components/schemas/Problem'
|
||
Forbidden:
|
||
description: 来源访问控制或客户端权限拒绝
|
||
content:
|
||
application/problem+json:
|
||
schema:
|
||
$ref: '#/components/schemas/Problem'
|
||
UnprocessableEntity:
|
||
description: 参数语法有效但违反业务约束
|
||
content:
|
||
application/problem+json:
|
||
schema:
|
||
$ref: '#/components/schemas/Problem'
|
||
TooManyRequests:
|
||
description: 超过全局或客户端速率限制
|
||
headers:
|
||
Retry-After:
|
||
schema:
|
||
type: integer
|
||
content:
|
||
application/problem+json:
|
||
schema:
|
||
$ref: '#/components/schemas/Problem'
|
||
ServiceUnavailable:
|
||
description: 权威存储不可用或服务正在排空
|
||
content:
|
||
application/problem+json:
|
||
schema:
|
||
$ref: '#/components/schemas/Problem'
|