Skip to content

HTTP API

BlueSkyXN edited this page May 4, 2026 · 2 revisions

HTTP API

事实来源:主仓 pr-88 @ a312645,路由清单与 schema 见 src/souwen/server/routes/、主仓 api-reference.md 与 /docs。

启动 API 服务后,所有 REST 端点都派发到 souwen.facade.*——和 CLI / Python API 走同一条路。本页按"端点目的"分组介绍最常用调用,错误码、限流、认证细节都在这里。完整字段表去主仓 docs/。


1. 启动

souwen serve --host 0.0.0.0 --port 8000      # 本地默认 8000
docker run -p 49265:49265 ghcr.io/blueskyxn/souwen   # 镜像默认 49265
入口 用途
GET / expose_docs=true 时重定向 /docs;否则返回 JSON 元信息
GET /docs Swagger UI
GET /redoc ReDoc
GET /openapi.json OpenAPI 3.1 schema
GET /panel Web UI(浏览器入口 /panel#/,前端 router 处理 hash)
GET /health 容器存活探针,无需认证
GET /readiness K8s readiness(仅本地检查),无需认证

生产建议设 expose_docs=false 关闭 /docs /redoc /openapi.json;/health /readiness /api/v1/* 不受影响。


2. 认证

所有需鉴权的端点用 Authorization: Bearer <password>:

export AUTH="Authorization: Bearer $SOUWEN_ADMIN_PASSWORD"
curl -H "$AUTH" http://localhost:8000/api/v1/admin/config

三角色映射(详见 Authentication and Roles):

端点群 角色要求 中间件
/api/v1/search/* · /api/v1/sources · /api/v1/whoami · /api/v1/wayback/cdx · /api/v1/wayback/check · /api/v1/youtube/* · /api/v1/bilibili/* · /api/v1/summarize · /api/v1/fetch/summarize User(未设密码时开放) check_search_auth
/api/v1/fetch · /api/v1/links · /api/v1/sitemap Admin(高 SSRF 风险) require_auth
/api/v1/admin/* · /api/v1/admin/wayback/save Admin(默认锁定) require_auth
/health · /readiness · /docs · /panel 无 —

GET /api/v1/whoami 返回当前角色与 features,前端用它做导航/页面级渲染:

{
  "role": "admin",
  "features": {
    "search": true, "raw_search": true, "fetch": true,
    "wayback_save": true,
    "config_read": "full", "config_write": true,
    "sources_config_read": true, "sources_config_write": true,
    "proxy_admin": true, "warp_admin": true,
    "doctor": true, "doctor_full": true
  },
  "guest_enabled": false
}

3. 搜索端点

GET /api/v1/search/paper

参数 类型 默认 说明
q string (1-500) 必填 关键词
sources string "openalex,arxiv" 源列表,逗号分隔
per_page int (1-100) 10 每源返回数
timeout float (1-300) | null null 端点硬超时;超时返回 504
curl "http://localhost:8000/api/v1/search/paper?q=transformer&per_page=5"

响应:

{
  "query": "transformer",
  "sources": ["openalex", "arxiv"],
  "results": [/* ... 多个 SearchResponse */],
  "total": 20,
  "meta": {
    "requested": ["openalex", "arxiv"],
    "succeeded": ["openalex", "arxiv"],
    "failed": []
  }
}
  • 任意源失败 → 出现在 meta.failed,不影响其他源。
  • 全部源失败 → 502 bad_gateway。
  • 超过 timeout → 504 gateway_timeout。

GET /api/v1/search/patent

参数同 paper,仅默认源不同:sources 默认 "google_patents"。

GET /api/v1/search/web

参数 类型 默认 说明
q string (1-500) 必填 关键词
engines string "duckduckgo,bing" 引擎列表
per_page int (1-50) 10 每引擎条数(主名)
max_results int (1-50) | null null 旧版别名;显式提供时优先于 per_page
timeout float (1-300) | null null 硬超时

兼容性:旧客户端继续用 max_results 也可;新客户端推荐 per_page。

GET /api/v1/search/images / videos

参数 类型 默认 说明
q string (1-500) 必填 关键词
max_results int (1-100) 20 最大结果数
region string "wt-wt" wt-wt 全球 / cn-zh 中国
safesearch string "moderate" on / moderate / off
timeout float (1-120) | null null 硬超时

GET /api/v1/sources

返回当前可用源列表(已过滤"必须凭据缺失/自建实例 URL 缺失");从运行时 live registry 派生,插件注册/注销实时生效。

{
  "paper": [
    {
      "name": "openalex",
      "needs_key": false,
      "key_requirement": "optional",
      "auth_requirement": "optional",
      "credential_fields": ["openalex_email"],
      "optional_credential_effect": "politeness",
      "integration_type": "open_api",
      "risk_level": "low",
      "stability": "stable",
      "default_enabled": true,
      "description": "OpenAlex 开放学术数据"
    }
  ],
  "patent": [...],
  "general": [...],
  "professional": [...],
  "fetch": [...]
}

general / professional 是 web domain 的兼容拆分;knowledge 显示为 wiki;archive 与跨域抓取归入 fetch。


4. 内容抓取端点

POST /api/v1/fetch(Admin)

curl -X POST "http://localhost:8000/api/v1/fetch" \
  -H "$AUTH" -H "Content-Type: application/json" \
  -d '{
    "urls": ["https://example.com"],
    "provider": "builtin",
    "timeout": 30
  }'
参数 类型 默认 说明
urls list[str] (1-20) 必填 目标 URL
provider string "builtin" 21 个 provider 之一
timeout float (1-120) 30 单 URL 超时秒

安全特性:

  • SSRF 防护:DNS 解析所有 A/AAAA 记录;私网(10/8、172.16/12、192.168/16)/ 回环 / 链路本地 / 保留段 / 组播段一律拒绝。
  • 逐跳重校验:重定向跟随过程中每一跳重新校验目标 IP,防止多跳 SSRF。
  • 被拦截的 URL 仍出现在 results 中,但 error 字段为 ssrf_blocked 类原因。

GET /api/v1/links(Admin)

curl -H "$AUTH" "http://localhost:8000/api/v1/links?url=https://example.com&limit=100"
参数 类型 默认 说明
url string 必填 页面 URL
base_url string null 仅保留前缀匹配
limit int (1-1000) 100 最多链接数

GET /api/v1/sitemap(Admin)

curl -H "$AUTH" "http://localhost:8000/api/v1/sitemap?url=https://example.com&discover=true"
参数 类型 默认 说明
url string 必填 sitemap URL 或网站根 URL
discover bool false true 时从 robots.txt 自动发现
limit int (1-50000) 1000 最多 URL 数

支持 sitemap.xml / sitemap index / gzipped。


5. 多媒体端点

YouTube(需 youtube_api_key,缺时返回 503)

curl "http://localhost:8000/api/v1/youtube/trending?region=US&max_results=20"
curl "http://localhost:8000/api/v1/youtube/video/dQw4w9WgXcQ"
curl "http://localhost:8000/api/v1/youtube/transcript/dQw4w9WgXcQ?lang=en"   # 零配额

Bilibili(可选 bilibili_sessdata)

错误码映射:BilibiliNotFound→404 · BilibiliAuthRequired→401 · BilibiliRateLimited→429 · BilibiliRiskControl→403 · BilibiliError→502。

curl "http://localhost:8000/api/v1/bilibili/video/BV1xx411c7m9"
curl "http://localhost:8000/api/v1/bilibili/search?keyword=编程&max_results=20&order=pubdate"
curl "http://localhost:8000/api/v1/bilibili/search/users?keyword=雷军&page=1"
curl "http://localhost:8000/api/v1/bilibili/search/articles?keyword=AI"

Wayback

# User
curl "http://localhost:8000/api/v1/wayback/cdx?url=https://example.com&from=20200101&to=20240101&limit=50"
curl "http://localhost:8000/api/v1/wayback/check?url=https://example.com&timestamp=20240301"

# Admin(IA 全局 ~15 req/min,注意限流)
curl -X POST -H "$AUTH" "http://localhost:8000/api/v1/admin/wayback/save?url=https://example.com"

6. LLM 摘要端点(详见 LLM Summary)

curl -X POST "http://localhost:8000/api/v1/summarize" \
  -H "Content-Type: application/json" \
  -d '{"q": "transformer", "domain": "paper", "limit": 5}'

curl -X POST "http://localhost:8000/api/v1/fetch/summarize" \
  -H "$AUTH" -H "Content-Type: application/json" \
  -d '{"urls": ["https://example.com"], "provider": "builtin"}'
  • 端点始终注册,但运行时要求 llm.enabled=true 且 llm.api_key 配置可用,否则 503 service_unavailable。

7. 管理端点(Admin 全集)

配置 / 健康

方法 路径 说明
GET /api/v1/admin/config 当前配置(敏感字段 ***)
POST /api/v1/admin/config/reload 重载 YAML + env
GET /api/v1/admin/config/yaml 读 YAML 或返回模板
PUT /api/v1/admin/config/yaml 保存并重载
GET /api/v1/admin/doctor 数据源健康摘要(不发真实请求)
GET /api/v1/admin/ping 仅 Admin 鉴权探活

频道配置

方法 路径 说明
GET /api/v1/admin/sources/config 全部源频道配置
GET /api/v1/admin/sources/config/{name} 单源
PUT /api/v1/admin/sources/config/{name} 运行时更新(不持久化)

Proxy / HTTP Backend

方法 路径 说明
GET/PUT /api/v1/admin/proxy 全局 proxy + proxy_pool
GET/PUT /api/v1/admin/http-backend 全局默认 + 按源覆盖

WARP

详见 Network and WARP。

方法 路径 说明
GET /api/v1/admin/warp 状态
GET /api/v1/admin/warp/config 配置视图
GET /api/v1/admin/warp/modes 5 种模式可用性
POST /api/v1/admin/warp/enable 启用
POST /api/v1/admin/warp/disable 禁用
POST /api/v1/admin/warp/register 注册(`backend=wgcf
POST /api/v1/admin/warp/test 测试出口
POST /api/v1/admin/warp/switch 切换模式
GET /api/v1/admin/warp/events SSE 实时事件流
GET /api/v1/admin/warp/components 组件状态(usque/wireproxy/wgcf)
POST /api/v1/admin/warp/components/install 运行时安装组件
POST /api/v1/admin/warp/components/uninstall 卸载

Plugins

详见 Plugins。

方法 路径 说明
GET /api/v1/admin/plugins 全部插件列表 + restart_required + install_enabled
GET /api/v1/admin/plugins/{name} 详情
GET /api/v1/admin/plugins/{name}/health 调插件 health_check
POST /api/v1/admin/plugins/{name}/enable 启用(重启生效)
POST /api/v1/admin/plugins/{name}/disable 禁用 + 运行时尽力卸载
POST /api/v1/admin/plugins/install pip 安装(需 SOUWEN_ENABLE_PLUGIN_INSTALL=1)
POST /api/v1/admin/plugins/uninstall pip 卸载
POST /api/v1/admin/plugins/reload 追加扫描 entry points

8. 错误响应

所有 4xx/5xx 错误统一格式:

{
  "error": "rate_limited",
  "detail": "请求过于频繁,每 60 秒最多 60 次",
  "request_id": "a1b2c3d4e5f6"
}

error 字段(机器可读)映射:

HTTP error
400 bad_request
401 unauthorized
403 forbidden
404 not_found
422 validation_error
429 rate_limited
500 internal_error
502 bad_gateway(如所有源失败)
503 service_unavailable(如缺必需 Key 的端点)
504 gateway_timeout
其他 error

详见 Error Codes。


9. 速率限制

/api/v1/search/* 默认 60 req / 60 s / IP(内存滑动窗口)。配置了 trusted_proxies 时,会从受信代理转发的 X-Forwarded-For 提取真实 IP。

429 响应附带:

Header 含义
Retry-After 建议重试等待秒数
X-RateLimit-Limit 窗口内最大请求数
X-RateLimit-Remaining 剩余配额(429 时为 0)
X-RateLimit-Reset 配额重置 Unix 时间戳

LLM 摘要单独受 llm.rate_limit_summarize / llm.rate_limit_fetch 控制。


10. 调用模板(cURL + Python)

Python httpx 客户端

import httpx

class SouWenClient:
    def __init__(self, base_url: str, password: str | None = None):
        self.base = base_url.rstrip("/")
        self.headers = {"Authorization": f"Bearer {password}"} if password else {}

    async def search_paper(self, q: str, sources: str = "openalex,arxiv", per_page: int = 10):
        async with httpx.AsyncClient(headers=self.headers, timeout=60) as c:
            r = await c.get(f"{self.base}/api/v1/search/paper",
                            params={"q": q, "sources": sources, "per_page": per_page})
            r.raise_for_status()
            return r.json()

    async def fetch(self, urls: list[str], provider: str = "builtin"):
        async with httpx.AsyncClient(headers=self.headers, timeout=60) as c:
            r = await c.post(f"{self.base}/api/v1/fetch",
                             json={"urls": urls, "provider": provider})
            r.raise_for_status()
            return r.json()

11. 接下来

Clone this wiki locally