接口文档
通过开放 API(OpenAPI)以编程方式管理你的站点。所有请求使用 HMAC-SHA256 签名鉴权。
概述
在控制台「API 管理」创建 API 应用,获得一对 APP_ID / APP_SECRET。APP_SECRET 仅在创建/重置时展示一次,请妥善保存。每个应用可设为「只读」或「读写」,其作用域为该应用所属账号下的站点。
API 基础地址
https://api.orbitshield.com请替换为平台提供的 API 域名。所有接口均需 HTTPS。
认证与签名(HMAC-SHA256)
每个请求需附带以下请求头。服务端用你的 APP_SECRET 重算签名比对,并校验时间戳偏差在 ±300 秒内(防重放)。
请求头
| X-Api-Id | APP_ID |
| X-Api-Timestamp | unix seconds |
| X-Api-Nonce | random string per request |
| X-Api-Sign | hex( HMAC-SHA256(APP_SECRET, stringToSign) ) |
签名算法
stringToSign =
METHOD + "\n" +
path + "\n" + // e.g. /api/v1/open/sites
rawQuery + "\n" + // e.g. page=1&pageSize=20 (empty if none)
timestamp + "\n" +
nonce + "\n" +
hex( sha256(body) ) // body = "" if no request body
X-Api-Sign = hex( HMAC-SHA256(APP_SECRET, stringToSign) )path 为不含域名与查询串的路径;rawQuery 为原始查询串(无则空);body 为原始请求体(无则空串)。换行符为 \n。
快速开始
1. 在控制台「API 管理」创建应用,拿到 APP_ID / APP_SECRET。
2. 用下面任一语言构造签名并发起请求(示例:列出你的站点)。
Node.js
import crypto from "node:crypto";
const API_BASE = "https://api.orbitshield.com";
const APP_ID = "ak_xxxxxxxxxxxx";
const APP_SECRET = "your_app_secret";
async function callOpenApi(method, path, { query = "", body = "" } = {}) {
const ts = Math.floor(Date.now() / 1000).toString();
const nonce = crypto.randomBytes(8).toString("hex");
const bodyHash = crypto.createHash("sha256").update(body).digest("hex");
const stringToSign = [method, path, query, ts, nonce, bodyHash].join("\n");
const sign = crypto.createHmac("sha256", APP_SECRET).update(stringToSign).digest("hex");
const url = API_BASE + path + (query ? "?" + query : "");
const res = await fetch(url, {
method,
headers: {
"X-Api-Id": APP_ID,
"X-Api-Timestamp": ts,
"X-Api-Nonce": nonce,
"X-Api-Sign": sign,
"Content-Type": "application/json",
},
body: body || undefined,
});
return res.json();
}
// List sites
console.log(await callOpenApi("GET", "/api/v1/open/sites", { query: "page=1&pageSize=20" }));Python
import time, os, hmac, hashlib, secrets, json, urllib.request
API_BASE = "https://api.orbitshield.com"
APP_ID = "ak_xxxxxxxxxxxx"
APP_SECRET = b"your_app_secret"
def call(method, path, query="", body=""):
ts = str(int(time.time()))
nonce = secrets.token_hex(8)
body_hash = hashlib.sha256(body.encode()).hexdigest()
string_to_sign = "\n".join([method, path, query, ts, nonce, body_hash])
sign = hmac.new(APP_SECRET, string_to_sign.encode(), hashlib.sha256).hexdigest()
url = API_BASE + path + (("?" + query) if query else "")
req = urllib.request.Request(url, data=body.encode() if body else None, method=method)
req.add_header("X-Api-Id", APP_ID)
req.add_header("X-Api-Timestamp", ts)
req.add_header("X-Api-Nonce", nonce)
req.add_header("X-Api-Sign", sign)
req.add_header("Content-Type", "application/json")
return json.load(urllib.request.urlopen(req))
print(call("GET", "/api/v1/open/sites", "page=1&pageSize=20"))cURL (bash)
#!/usr/bin/env bash
API_BASE="https://api.orbitshield.com"
APP_ID="ak_xxxxxxxxxxxx"
APP_SECRET="your_app_secret"
METHOD="GET"; PATH_="/api/v1/open/sites"; QUERY="page=1&pageSize=20"; BODY=""
TS=$(date +%s)
NONCE=$(openssl rand -hex 8)
BODY_HASH=$(printf '%s' "$BODY" | openssl dgst -sha256 | awk '{print $2}')
STS=$(printf '%s\n%s\n%s\n%s\n%s\n%s' "$METHOD" "$PATH_" "$QUERY" "$TS" "$NONCE" "$BODY_HASH")
SIGN=$(printf '%s' "$STS" | openssl dgst -sha256 -hmac "$APP_SECRET" | awk '{print $2}')
curl -s "$API_BASE$PATH_?$QUERY" \
-H "X-Api-Id: $APP_ID" \
-H "X-Api-Timestamp: $TS" \
-H "X-Api-Nonce: $NONCE" \
-H "X-Api-Sign: $SIGN"接口列表
所有接口作用域为应用所属账号的站点;标注「读写」的接口要求应用为读写权限。
| 方法 | 路径 | 权限 | 说明 |
|---|---|---|---|
| GET | /api/v1/open/sites | 只读 | 列出账号下所有站点 |
| GET | /api/v1/open/sites/{id}/config | 只读 | 获取指定站点配置 |
| PUT | /api/v1/open/sites/{id}/config | 读写 | 全量更新站点配置(乐观并发,回传 version) |
| PATCH | /api/v1/open/sites/{id}/config | 读写 | 局部更新:只提交改动字段,后端按 JSON Merge Patch 深合并 |
| POST | /api/v1/open/refresh | 读写 | 刷新(清除)缓存 |
| POST | /api/v1/open/preheat | 读写 | 预热缓存 |
响应格式
{ "code": 0, "message": "ok", "data": { /* ... */ } }成功返回 code=0;失败返回非 0 code 与 message。
站点配置参数(SiteConfig)
GET /sites/{id}/config 返回、PUT /sites/{id}/config 提交的都是同一个完整配置对象,含 6 个分组:origin(源站)、cache(缓存)、compress(压缩)、https、security(安全)、advanced(高级)。
重要:更新为「整份覆盖」,请按读-改-写流程
两种方式:① PUT 整份覆盖——先 GET 拿完整配置与 version,改后带 version 整份提交。② PATCH 局部更新(推荐小改动)——只提交改动的字段/段(如 {"https":{"http2":true},"version":N}),后端读当前配置按 JSON Merge Patch 深合并,未提交字段保持不变;数组提供即整体替换,值为 null 表示删除该键。两者都按 version 做乐观并发,冲突返回 409。
origin源站
| 字段 | 类型 | 说明 |
|---|---|---|
| scheme | string | 回源协议:http | https | follow(协议跟随) |
| balance | string | 负载均衡:roundrobin(轮询) | chash(源地址哈希) | cookie |
| balanceArg | string | balance=cookie 时的 cookie 名 |
| nodes | NodeCfg[] | 源站节点数组(见下表) |
| passHost | string | 回源 Host:pass(透传) | rewrite(改写为 hostValue) |
| hostValue | string | passHost=rewrite 时的 Host 值 |
| sni | string | HTTPS 回源 SNI(空=用回源 Host) |
| range | bool | 透传 Range(分片/断点续传回源) |
| timeout | int | 回源超时(秒) |
| health | HealthCfg | 主动健康检查(见下表) |
| keepalive | bool | 回源长连接 |
origin.nodes[]源站节点 NodeCfg
| 字段 | 类型 | 说明 |
|---|---|---|
| host | string | 源站 IP 或域名 |
| port | int | 端口 |
| weight | int | 权重 |
| role | string | main(主) | backup(备,主故障转移) |
| line | string | 线路名(如 主线路/备线路) |
origin.health健康检查 HealthCfg
| 字段 | 类型 | 说明 |
|---|---|---|
| fails | int | 连续失败几次摘除(0=关) |
| interval | int | 探测间隔(秒) |
| timeout | int | 单次探测超时(秒) |
cache缓存
| 字段 | 类型 | 说明 |
|---|---|---|
| enable | bool | 是否开启缓存 |
| rules | CRuleCfg[] | 缓存规则数组(见下表) |
| ignoreCacheControl | bool | 忽略源站 Cache-Control,按规则 TTL |
| ignoreUrlParams | bool | 缓存键忽略 URL query |
| httpsShared | bool | http/https 共享同一缓存键 |
cache.rules[]缓存规则 CRuleCfg
| 字段 | 类型 | 说明 |
|---|---|---|
| type | string | 匹配类型:suffix(后缀) | dir(目录) | full(完整路径) |
| content | string | 匹配值(如 js|css|png 或 /static/ 或 /a.html) |
| ttl | int | 缓存时长(秒),0=不缓存 |
| prio | int | 优先级(数字小者优先) |
compress压缩
| 字段 | 类型 | 说明 |
|---|---|---|
| gzip | string[] | 开启 gzip 的 MIME 列表;空数组=关闭 |
httpsHTTPS
| 字段 | 类型 | 说明 |
|---|---|---|
| certId | string | 绑定证书 ID(证书由证书接口/控制台管理) |
| forceHttps | bool | 强制 HTTPS(http 301 跳 https) |
| http2 | bool | 开启 HTTP/2 |
| hsts | bool | 开启 HSTS |
| minTls | string | 最低 TLS 版本:1.0 | 1.1 | 1.2 | 1.3 |
security安全(各子项为 null=不启用)
| 字段 | 类型 | 说明 |
|---|---|---|
| waf | object|null | WAF:{mode: observe|intercept|ban|off, level: normal|strict, ai, scope: smart|all, categories, exceptions} |
| cc | object|null | CC 防护:{mode: off|default|normal|strict|captcha, threshold, window} |
| referer | object|null | 防盗链:{mode: white|black, list[]} |
| ipRule | object|null | IP 黑白名单:{mode: white|black, cidrs[]} |
| region | object|null | 区域封禁:{mode: white|black, areas[](国家/省市码)} |
| originProtect | object|null | 源站保护:{qps, window} |
| acl | object|null | 精准访问控制(多规则集,结构较复杂,建议控制台配置后经 GET 获取) |
advanced高级
| 字段 | 类型 | 说明 |
|---|---|---|
| websocket | bool | 开启 WebSocket 透传 |
| respHeaders | {name,value}[] | 自定义响应头 |
| reqHeaders | {name,value}[] | 自定义回源请求头 |
| errorPages | object[] | 源站错误页:{status, mode: origin|html|url|charity404, html?, url?} |
| blockPage | object|null | 安全拦截页:{mode, ...} |
| redirects | object[] | URL 重定向:{type: prefix|exact|regex, match, target, code:301/302/307/308, keepQuery} |
| rewrites | object[] | URL 重写(透明改回源 URI):{type, match, target} |
| mobileRedirect | object|null | 移动端跳转:{enable, url} |
| dropEtag | bool | 移除响应头 ETag |
示例:开启 HTTP/2 + 强制 HTTPS(节选 https 段)
"https": {
"certId": "12",
"forceHttps": true,
"http2": true,
"hsts": true,
"minTls": "1.2"
}示例:更新源站(节选 origin 段)
"origin": {
"scheme": "https",
"balance": "roundrobin",
"passHost": "rewrite",
"hostValue": "origin.example.com",
"sni": "",
"range": true,
"timeout": 30,
"keepalive": true,
"nodes": [
{ "host": "1.2.3.4", "port": 443, "weight": 1, "role": "main", "line": "主线路" }
],
"health": { "fails": 3, "interval": 10, "timeout": 5 }
}以上为节选;实际 PUT 请提交 GET 返回的完整对象(含未改动的其它分组)+ version。
错误码
| HTTP | 场景 |
|---|---|
| 400 | 参数/请求体格式错误 |
| 401 | 缺少或无效签名、时间戳超出 ±300s、APP_ID 无效或应用已禁用 |
| 403 | 只读应用调用写接口,或无权限 |
| 404 | 站点不存在或不属于该应用账号 |
| 409 | 配置版本冲突(已被其他会话修改) |