API 参考

BlankTrail Proxy 提供了一个本地 HTTP API,让你能够开放端口、配置身份,并自动化控制面板所能完成的一切操作。本页介绍基础 URL、身份验证和约定规范。

基础 URL

所有端点都位于与控制面板相同的主机和端口下的 /api/v1 前缀之下:

http://127.0.0.1:8891/api/v1

API 与控制面板共用同一个源,因此来自您自己的脚本和工具的调用可以开箱即用。

身份验证

该 API 采用默认拒绝策略:几乎每个端点都需要身份验证。有两种身份验证方式:

  • API 密钥 —— 通过 X-API-Key 请求头发送。最适合脚本和自动化。
  • 会话 Cookie —— 通过登录获取;供浏览器控制面板使用。

您可以在控制面板的“设置”对话框中查找和轮换您的 API 密钥。在每个请求上都要发送它:

curl -H "X-API-Key: YOUR_API_KEY" http://127.0.0.1:8891/api/v1/status
重要API 密钥可完全控制您的端口。请对其保密,并限制对控制面板端口的网络访问(绑定到 localhost,或在服务器上使用 SSH 隧道)。

约定规范

  • 请求和响应均为 JSON。对于带有请求体的请求,请发送 Content-Type: application/json。
  • 配置始终在 JSON 请求体中发送,绝不通过查询字符串发送。
  • 该 API 在 /api/v1 下进行版本管理。破坏性变更将迁移到新的版本前缀。

状态码

错误响应体始终一致:一个带 error 字段和英文文本的对象;部分拒绝还会附带 code 字段,即机器可读的原因。各接口的说明中给出了这些文本:据此区分同为 400 的不同原因。405 是例外:它由路由器以纯文本返回,而非 JSON。

状态码含义
200 OK成功。
202 Accepted已接受并在后台执行——启动更新时即以此作答。
400 Bad Request输入有误:请求体无法解析、字段缺失或取值不被允许。
401 Unauthorized未发送 API 密钥或密钥错误。请检查请求头名称:X-API-Key。
403 Forbidden被拒绝的原因不是密钥而是状态:许可未激活(订阅已结束,或 24 小时内未连接授权服务器),或该功能需要 Pro 套餐。
404 Not Found对象不存在:路径未注册、端口未开放,或条目未找到。
405 Method Not Allowed路径存在但方法不对——例如对只读接口发送 PUT。该状态码由路由器本身返回,而不是由处理程序返回。
409 Conflict状态存在冲突:端口已被占用、名称已存在,或网关正在使用中。
429 Too Many Requests过于频繁——例如重复提交问题报告。请降低频率后重试。
500 Internal Server Error应用内部发生了意外错误。
501 Not Implemented该组件在此构建中未编译或未接入——例如未配置身份验证时,控制面板登录即以此作答。
502 Bad Gateway对外请求失败:Cabinet 不可达,或对该地址的访问未能完成。
503 Service Unavailable此刻无法作答:没有空闲端口、服务未启动,或调试钩子未接入。
注意不要混淆 403 与 401:401 关乎密钥,403 关乎权限。已正常运行数月的客户端在与授权服务器失联一天后,会在 POST /api/v1/system/leak-audit、POST /api/v1/upstream/test、POST /api/v1/scraper/probe、POST /api/v1/ovpn/ping 与 POST /api/v1/gateway/subs/{name}/refresh 上收到 403——而此时密钥是正确的。

按主题查阅参考

  • 端口与流量 —— 开放、关闭、列出和配置端口;测试上游代理。
  • 配置文件与路由 —— 身份、预设、域名规则和网关。
  • 端口池 —— 从代理列表开放和管理端口池。
  • 许可证与访问 —— 许可证状态、身份验证以及 CA 证书。

服务类接口

这些接口不属于业务流程本身,而是伴随其左右:确认应用存活、在排查期间提高日志详细度、查询更新,以及设置全局路由规则。

GET/api/v1/log_level需要鉴权

当前的日志级别。

示例 (curl)
curl -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/log_level
响应
{
  "level": "info"
}
PUT/api/v1/log_level需要鉴权

在排查期间提高详细度:debug 会写入明显更多内容,并持续到下次重启。

参数类型必填说明
levelstring是debug、info、warn 或 error。
请求体
{ "level": "debug" }
示例 (curl)
curl -X PUT -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"level":"debug"}' \
  http://127.0.0.1:8891/api/v1/log_level
响应
{
  "level": "debug"
}
  • 其他取值一律返回 400 “level must be one of: debug, info, warn, error”。
GET/api/v1/update/status需要鉴权

已安装的版本以及是否有新版本:没有更新时 available 为空;state 显示更新器当前的状态。

示例 (curl)
curl -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/update/status
响应
{
  "current": "1.3.2",
  "available": "",
  "state": "idle",
  "last_error": "",
  "download_url": ""
}
  • 在未包含自更新的构建中返回 404 “self-update not available”。
POST/api/v1/update需要鉴权

安装 /update/status 所报告的更新。应用会自行重启。

示例 (curl)
curl -X POST -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/update
响应
{
  "status": "started"
}
  • 🔴 响应为 202 Accepted 而不是 200:更新已被接受并在后台执行,并非在响应返回时已经完成。请通过轮询 /update/status 等待其结束。
  • 若没有可安装的更新,返回 409 “no update available”;在未包含自更新的构建中返回 404 “self-update not available”。
GET/api/v1/domain_routing需要鉴权

简单路由规则:一组域名以及它们共用的出口代理。列表为空表示该规则关闭。带名称的详细规则位于 /domain_rules。

示例 (curl)
curl -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/domain_routing
响应
{
  "domains": ["example.com", "*.example.net"],
  "proxy": "socks5://203.0.113.10:1080"
}
PUT/api/v1/domain_routing需要鉴权

整体设置简单规则:域名与代理。域名列表为空即关闭该规则。

参数类型必填说明
domainsarray是域名及形如 *.example.net 的掩码。
proxystring是这些域名所使用的出口代理。
请求体
{ "domains": ["example.com"], "proxy": "socks5://203.0.113.10:1080" }
示例 (curl)
curl -X PUT -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"domains":["example.com"],"proxy":"socks5://203.0.113.10:1080"}' \
  http://127.0.0.1:8891/api/v1/domain_routing
响应
{
  "domains": ["example.com"],
  "proxy": "socks5://203.0.113.10:1080"
}
  • 若域名或代理地址格式有误,返回 400 并附说明。
PUT/api/v1/idle_timeout需要鉴权

适用于没有自身设置的端口的全局空闲超时。0 表示不关闭。

参数类型必填说明
secondsint是端口自动关闭前的空闲秒数;0 表示不关闭。
请求体
{ "seconds": 1800 }
示例 (curl)
curl -X PUT -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"seconds":1800}' \
  http://127.0.0.1:8891/api/v1/idle_timeout
响应
{
  "idle_timeout_seconds": 1800
}
  • 取负值时返回 400 “seconds must be >= 0”。设置了自身覆盖值的端口(PUT /api/v1/port/{port}/idle)不会采用该值。

问题报告

该报告会收集日志与端口状态并发送给支持团队。发送前可完整查看——那正是将要发送的同一份文件。

GET/api/v1/bug-report/status需要鉴权

报告发送是否已启用,以及上次运行是否非正常退出——若是,控制面板会主动提示发送报告。

示例 (curl)
curl -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/bug-report/status
响应
{
  "enabled": true,
  "unclean_previous_exit": false
}
  • enabled=false 表示在没有有效许可的情况下无法发送。
POST/api/v1/bug-report/preview需要鉴权

生成报告并展示,但不发送任何内容。

示例 (curl)
curl -X POST -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/bug-report/preview
响应
{
  "report": { "version": 1, "ports": [ … ], "log": [ … ] },
  "notes_included": false
}
  • 若报告收集功能未接入,返回 404 “bug report not available”;500 “failed to build report”。
POST/api/v1/bug-report/send需要鉴权

把报告连同您的描述一起发送给支持团队。

参数类型必填说明
descriptionstring是发生了什么。该字段必填:去除空白后为空将被拒绝。
请求体
{ "description": "更换出口后端口不再返回 200" }
示例 (curl)
curl -X POST -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"description":"port stopped returning 200 after an egress change"}' \
  http://127.0.0.1:8891/api/v1/bug-report/send
响应
{
  "status": "sent",
  "bug_report_id": "br-7f3a1c9d"
}
  • 未填写描述时返回 400 “description required”;403 “activate your license to send a bug report”;404 “bug report not available”;发送过于频繁时返回 429;若支持服务器不可达,返回 502。
  • 请求体上限为 64 KiB。
POST/api/v1/bug-report/dismiss需要鉴权

拒绝所提示的报告:在本次运行剩余时间内不再显示非正常退出提示。

示例 (curl)
curl -X POST -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/bug-report/dismiss
响应
{
  "status": "dismissed"
}
  • 该标记仅存于内存:若下次运行确实再次非正常退出,它会被重新置位。

诊断

当应用行为异常、需要在支持请求中附上数据而非描述时,可使用这些路径。它们并非产品接口:其格式由运行时决定,可能在版本之间发生变化。

GET/api/v1/debug需要鉴权

进程自身的快照:goroutine、系统线程、句柄、内存与运行时间。若应用变得沉重,这是首先应附上的内容。

示例 (curl)
curl -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/debug
响应
{
  "goroutines": 142,
  "threads": 21,
  "handles": 380,
  "open_ports": 2,
  "uptime": "3h14m22s",
  "memory": {
    "alloc_mb": 96,
    "total_alloc_mb": 8140,
    "sys_mb": 310,
    "heap_objects": 410000,
    "heap_inuse_mb": 120,
    "heap_released_mb": 64,
    "gc_cycles": 1830,
    "stack_inuse_mb": 6
  }
}
  • handles 字段始终存在,但只在 Windows 上有意义:该数值由系统自身统计;在其他平台上它恒为 0。

性能剖析(pprof)

十一个标准的 Go 路径,使用普通 API 密钥即可访问。它们返回的是进程内部信息而非用户数据,但与其余 API 一样需要密钥。

路径返回内容
/debug/pprof/索引:可用性能剖析的列表。
/debug/pprof/heap堆快照——内存增长时应从这里入手。
/debug/pprof/goroutine所有 goroutine 及其栈——出现卡住时应从这里入手。
/debug/pprof/allocs自启动以来的全部内存分配。
/debug/pprof/profileCPU 剖析。🔴 它会保持连接 30 秒——这不是卡死。
/debug/pprof/trace执行跟踪。
/debug/pprof/blockgoroutine 在阻塞操作上的等待情况。
/debug/pprof/mutex互斥锁竞争。
/debug/pprof/threadcreate系统线程创建。
/debug/pprof/cmdline进程的命令行。
/debug/pprof/symbol把地址解析为函数名。

为报告采集堆与 goroutine:curl -H "X-API-Key: YOUR_API_KEY" -o heap.pprof http://127.0.0.1:8891/debug/pprof/heap,goroutine 同理。使用 go tool pprof heap.pprof 打开它们。

解题器的调试特征机制

警告以下四个接口仅在应用启动时设置了环境变量 BLANKTRAIL_SOLVER_DEBUG_API=1 的情况下才存在。比较是严格的:取值 0 或 true 都不会启用它们。该变量在启动时只读取一次——之后再设置对运行中的进程无效。未设置时,这些路由根本不会注册,请求会得到 404:不存在的接口不应暴露自己的存在。

该机制只为一件事而存在:在不重建、不发布资源包的情况下检查挑战特征是否匹配。在此之前,这样一个循环需要重建资源包、签名、发布,并等待客户端重新读取资源包,最长达半小时。

GET/api/v1/debug/signatures需要鉴权

报告当前是否在资源包特征库之上叠加了调试特征层,以及其中有多少条目。

示例 (curl)
curl -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/debug/signatures
响应
{
  "debug_active": true,
  "debug_vendors": 3
}
  • 若已设置开关但该构建未接入解题器钩子,返回 503 “solver debug hooks not wired”。这不是 404:路由本身存在,区分这两种状态很重要。
POST/api/v1/debug/signatures需要鉴权

把所提交的特征集合作为独立层叠加到资源包特征库之上——无需重建资源包、签名或发布。

请求体
{ "Version": 7, "Vendors": [ { "…": "…" } ], "NavHints": [ ] }
示例 (curl)
curl -X POST -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  --data-binary @signatures.json \
  http://127.0.0.1:8891/api/v1/debug/signatures
响应
{
  "installed": 3,
  "dropped": 1
}
  • 请求体是与资源包相同格式的特征库。installed 表示被接受的厂商数量,dropped 表示所提交条件中被丢弃的数量。
  • 该层可经受任意次数的资源包更新,只有显式 DELETE 才会移除。安装动作会以警告写入日志——被遗忘的层不应无声无息地留存。
  • 503 “solver debug hooks not wired”;400 “invalid JSON body”。
DELETE/api/v1/debug/signatures需要鉴权

移除调试特征层,让解题器回到资源包特征库。

示例 (curl)
curl -X DELETE -H "X-API-Key: YOUR_API_KEY" \
  http://127.0.0.1:8891/api/v1/debug/signatures
响应
{
  "cleared": true
}
  • 若未接入钩子,返回 503 “solver debug hooks not wired”。
POST/api/v1/port/{port}/solve_probe需要鉴权

让解题器经由指定端口访问给定地址,并返回它在那里看到的内容——无论特征是否匹配。

参数类型必填说明
urlstring是要让解题器访问的地址。
solvebool否false(默认)只识别厂商与页面性质,约需一秒。true 还会强制求解。
请求体
{ "url": "https://example.com/", "solve": true }
示例 (curl)
curl -X POST -H "X-API-Key: YOUR_API_KEY" -H "Content-Type: application/json" \
  -H "Accept-Language: ru-RU,ru;q=0.9" \
  -d '{"url":"https://example.com/","solve":true}' \
  http://127.0.0.1:8891/api/v1/port/20134/solve_probe
  • 🔴 当 solve=true 时,此处刻意不设人为超时:强制求解确实需要数十秒,某些验证甚至长达一分半。请求并没有卡死。
  • 该请求的 Accept-Language 头会被原样传入任务:启动语言会影响结果,若不传入,求解就会带着出口节点的语言而非所请求的语言。
  • 503 “solver debug hooks not wired”;400 “url is required”;若访问本身失败,返回 502 并附带错误文本。