需要可复用的客户端? 下载 PHP、Python、Node.js 官方轻量 SDK。下方快速示例与原有链接继续保留。
接入示例代码
参考 Console 的多语言示例,以下代码演示创建 GFW 全量检测批次,再按 batch_id 分页读取结果。示例仅供阅读和复制,网页不会执行任何 API 请求。
查看创建批次与结果分页示例
#!/usr/bin/env bash
set -euo pipefail
# Requires curl + jq. Set these server-side environment variables first.
: "${WEAVEBIT_API_KEY:?Set your API key}"
: "${WEAVEBIT_REQUEST_ID:?Set and persist one ID for this logical create}"
base='https://api.weavebit.com/v2'
request() {
local path="$1" body="$2" response
response=$(curl --silent --show-error --fail-with-body --max-time 30 \
-X POST "$base/$path" \
-H "Authorization: Bearer $WEAVEBIT_API_KEY" \
-H 'Content-Type: application/json' \
-H "Idempotency-Key: $WEAVEBIT_REQUEST_ID" \
--data "$body") || return 1
if ! jq -e '.code == 0' >/dev/null <<<"$response"; then
printf 'API operation failed; inspect code and message.\n' >&2
return 1
fi
printf '%s' "$response"
}
body='{"check_type":"gfw_full_domain_check","target":[{"domain":"example.com"}],"nodes":["NODE_ID_FROM_GET_NODES"]}'
# Replace the node placeholder using get_nodes; review estimate before create.
# Create can incur charges. Reuse the same body and request ID for a retry.
created=$(request task/create "$body")
batch_id=$(jq -er '.batch_id' <<<"$created")
printf 'Persist batch_id: %s\n' "$batch_id"
first=$(request task/result "$(jq -cn --arg id "$batch_id" \
'{batch_id:$id,page:1,page_size:200}')")
pages=$(jq -er '.pagination.pages' <<<"$first")
(( pages >= 1 && pages <= 5 )) || exit 1
jq '{batch_status,datas,pagination}' <<<"$first"
for ((page=2; page<=pages; page++)); do
request task/result "$(jq -cn --arg id "$batch_id" --argjson p "$page" \
'{batch_id:$id,page:$p,page_size:200}')" | jq '{batch_status,datas,pagination}'
done
# One read pass, not polling. Pending/running: resume later with this batch_id.
# Retain required results before expires_at; never turn null into success.<?php
// PHP 8+ with cURL. Set and persist these server-side environment variables.
$key = getenv('WEAVEBIT_API_KEY');
$requestId = getenv('WEAVEBIT_REQUEST_ID');
if (!$key || !$requestId) {
throw new RuntimeException('Set API key and a persistent request ID.');
}
function api(string $path, array $body): array {
global $key, $requestId;
$curl = curl_init('https://api.weavebit.com/v2/' . $path);
curl_setopt_array($curl, [
CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30, CURLOPT_CONNECTTIMEOUT => 10,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $key,
'Content-Type: application/json', 'Idempotency-Key: ' . $requestId],
CURLOPT_POSTFIELDS => json_encode($body, JSON_THROW_ON_ERROR),
]);
$raw = curl_exec($curl);
$status = curl_getinfo($curl, CURLINFO_RESPONSE_CODE);
curl_close($curl);
if ($raw === false || $status < 200 || $status >= 300) {
throw new RuntimeException('HTTP request failed; preserve creation idempotency.');
}
$data = json_decode($raw, true, 512, JSON_THROW_ON_ERROR);
if (($data['code'] ?? null) !== 0) {
throw new RuntimeException('API code: ' . ($data['code'] ?? 'missing'));
}
return $data;
}
$body = ['check_type' => 'gfw_full_domain_check',
'target' => [['domain' => 'example.com']],
'nodes' => ['NODE_ID_FROM_GET_NODES']];
// Fetch current nodes and review estimate first. Create can incur charges.
$created = api('task/create', $body);
$batchId = $created['batch_id']; // Persist this before querying results.
$first = api('task/result', ['batch_id' => $batchId, 'page' => 1, 'page_size' => 200]);
$pages = (int)$first['pagination']['pages'];
if ($pages < 1 || $pages > 5) throw new RuntimeException('Invalid page count.');
$rows = $first['datas'];
for ($page = 2; $page <= $pages; $page++) {
$result = api('task/result', ['batch_id' => $batchId, 'page' => $page, 'page_size' => 200]);
$rows = array_merge($rows, $result['datas']);
}
echo json_encode(['batch_id' => $batchId, 'batch_status' => $first['batch_status'],
'datas' => $rows], JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR);
// One read pass. If pending/running, resume later with the stored batch_id.
// Retain results before expires_at, preserving 0, 1, and null separately.# Python 3. Standard library only; credentials stay on your server.
import json
import os
from urllib.request import Request, urlopen
key = os.environ["WEAVEBIT_API_KEY"]
request_id = os.environ["WEAVEBIT_REQUEST_ID"] # Persist for this logical create.
def api(path, body):
request = Request("https://api.weavebit.com/v2/" + path,
data=json.dumps(body).encode("utf-8"), method="POST",
headers={"Authorization": "Bearer " + key,
"Content-Type": "application/json",
"Idempotency-Key": request_id})
# HTTP errors raise; do not blindly retry creation with a new ID.
with urlopen(request, timeout=30) as response:
data = json.load(response)
if data.get("code") != 0:
raise RuntimeError("API code: " + str(data.get("code")))
return data
body = {"check_type": "gfw_full_domain_check",
"target": [{"domain": "example.com"}],
"nodes": ["NODE_ID_FROM_GET_NODES"]}
# Replace the node placeholder and review estimate first; create can incur charges.
created = api("task/create", body)
batch_id = created["batch_id"] # Persist this before querying results.
first = api("task/result", {"batch_id": batch_id, "page": 1, "page_size": 200})
pages = int(first["pagination"]["pages"])
if not 1 <= pages <= 5:
raise RuntimeError("Invalid page count")
rows = list(first["datas"])
for page in range(2, pages + 1):
result = api("task/result", {"batch_id": batch_id, "page": page, "page_size": 200})
rows.extend(result["datas"])
print(json.dumps({"batch_id": batch_id, "batch_status": first["batch_status"],
"datas": rows}, indent=2))
# One read pass. If pending/running, resume later with the stored batch_id.
# Retain results before expires_at; preserve None (null), 0, and 1 separately.// Node.js 18+. Credentials and a persistent request ID belong on your server.
const key = process.env.WEAVEBIT_API_KEY;
const requestId = process.env.WEAVEBIT_REQUEST_ID;
if (!key || !requestId) throw new Error('Set API key and a persistent request ID.');
async function api(path, body) {
const response = await fetch(`https://api.weavebit.com/v2/${path}`, {
method: 'POST', signal: AbortSignal.timeout(30000),
headers: { Authorization: `Bearer ${key}`, 'Content-Type': 'application/json',
'Idempotency-Key': requestId },
body: JSON.stringify(body),
});
if (!response.ok) throw new Error(`HTTP ${response.status}; preserve creation idempotency.`);
const data = await response.json();
if (data.code !== 0) throw new Error(`API code: ${data.code}`);
return data;
}
async function main() {
const body = { check_type: 'gfw_full_domain_check',
target: [{ domain: 'example.com' }], nodes: ['NODE_ID_FROM_GET_NODES'] };
// Fetch current nodes and review estimate first; create can incur charges.
const created = await api('task/create', body);
const batchId = created.batch_id; // Persist this before querying results.
const first = await api('task/result', { batch_id: batchId, page: 1, page_size: 200 });
const pages = first.pagination.pages;
if (!Number.isInteger(pages) || pages < 1 || pages > 5) throw new Error('Invalid page count');
const rows = [...first.datas];
for (let page = 2; page <= pages; page++) {
const result = await api('task/result', { batch_id: batchId, page, page_size: 200 });
rows.push(...result.datas);
}
console.log(JSON.stringify({ batch_id: batchId, batch_status: first.batch_status,
datas: rows }, null, 2));
// One read pass. If pending/running, resume later with the stored batch_id.
// Retain results before expires_at; preserve 0, 1, and null separately.
}
main().catch(error => { console.error(error.message); process.exitCode = 1; });API v2 用于异步批量网络检测:先预估费用,再创建批次,随后查询进度并保存结果。它支持七种检测方式。Console 的持续监控任务目前提供 DNS 污染与 GFW 域名全量两类;需要平台安排定时执行和通知时,使用监控入口。
API 返回的是指定目标、方法、网络与时间下的观测及判定,不是完整浏览器体验或故障责任认定。判定值与适用边界见结果解读,实际接入步骤见批量检测指南。
认证与响应
Base URL 为 https://api.weavebit.com/v2。以下 v2 接口使用 POST、UTF-8 JSON 和同一个账户 API Key:
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json
在 Console 管理 API Key。只在服务端保存密钥,不放进网页脚本、请求 URL、版本库或日志。v2 响应包含整数 code 和字符串 message;code=0 表示本次接口请求成功。HTTP 请求成功与业务成功、检测正常是不同概念,必须逐层检查。
七种检测方法与目标参数
check_type 使用下面的小写标识。target 是对象数组,每个对象按方法填写参数;除 DNS 污染检测外,还要提供 nodes。
| check_type | 必填目标字段 | 可选目标字段与默认值 | 输出与边界 |
|---|---|---|---|
dns_resolve |
domain |
resolver: "" |
解析状态与 A 记录;解析成功不等于没有污染 |
icmp_ping_check |
ip |
count: 4 |
ICMP 状态、延迟与丢包;不响应不等于业务宕机 |
tcp_connect_check |
ip |
port: 443 |
指定 IPv4 与端口的连接状态,不检查业务响应 |
http_host_reset_check |
domain |
port: 80, path: "/" |
HTTP Host 请求状态;合法响应不保证 200 或页面正确 |
tls_sni_handshake_check |
domain |
port: 443 |
目标 SNI 的握手状态,不是完整证书审计 |
dns_pollution_check |
domain |
无 | DNS 污染判定 result_code、解析 status 与 a;请求省略 nodes |
gfw_full_domain_check |
domain |
http_port: 80, tls_port: 443 |
DNS 污染、HTTP Host、TLS SNI 三个维度及 overall_result,不是全部七种检测 |
domain 必须是纯域名,最长 253 字符,不包含协议、路径、查询参数、端口、空格或 @。Unicode 国际化域名会规范化为小写 ASCII Punycode;用 check_id 关联自己的业务目标。ip 目前只接受 IPv4。端口为 1–65535 的整数,count 为 1–20;path 以 / 开头,最长 2048 字符。resolver 为 IPv4 地址,留空使用检测网络的系统 DNS。
每次预估或创建提交 1–1000 个目标。规范化后相同的目标仍可能作为独立任务计费,提交前在客户端去重。不要把域名与 IP 混填,也不要把 http_port、tls_port 当作单独 HTTP 或 TLS 方法的 port。
接口清单
下面路径均接在 v2 Base URL 后。查询接口不会创建检测任务;create 会创建可能产生费用的批次。
| 路径 | 请求内容 | 用途 |
|---|---|---|
/task/get_nodes |
{} |
获取当前可用节点 |
/task/estimate |
check_type, target, 必要时 nodes |
预估本次组合费用 |
/task/create |
与预估相同的检测参数 | 创建异步批次,可带幂等请求头 |
/task/result |
batch_id,可选 page, page_size |
查询批次的一页目标 |
/task/get_batches |
可选 page: 1, page_size: 20, status, check_type |
查看最近 24 小时的批次元数据,不返回目标列表 |
/task/get_balance |
{} |
查询账户余额、预留与可用余额 |
get_batches.page_size 范围为 1–100,status 可筛选 pending、running 或 completed,check_type 可筛选检测方法。调用 result 必须提供创建返回的 batch_id,不能仅传 check_id;check_id 用于在返回列表中识别与关联目标。
获取与选择节点
curl -X POST 'https://api.weavebit.com/v2/task/get_nodes' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{}'
响应 datas[] 包含 node_id、node_zh_name、node_en_name,父节点还包含 children[]。程序使用 node_id 关联,不依赖可读名称。nodes 可为最多 100 个节点代码组成的数组,或字符串 "all";父节点会展开为当前可用子节点。节点可用性会变化,按客户地区与运营商选择,并在创建前重新预估。
DNS 污染检测请求不传 nodes。公开接口仅需输入域名并读取结果,不需要了解检测的内部实现。
预估与创建
先以相同的 JSON 请求体调用 /task/estimate,确认预估和可用余额,再调用 /task/create。下面是 GFW 全量示例;节点占位符必须替换为 get_nodes 当前返回的代码,域名替换为有权限检测的目标。
curl -X POST 'https://api.weavebit.com/v2/task/create' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: YOUR_UNIQUE_REQUEST_ID' \
-d '{
"check_type": "gfw_full_domain_check",
"target": [{"domain": "example.com"}],
"nodes": ["NODE_ID_FROM_GET_NODES"]
}'
单独 DNS 污染检测的请求体为:
{
"check_type": "dns_pollution_check",
"target": [{"domain": "example.com"}]
}
预估响应 data 包含 unit_price、currency、planned_node_count、planned_target_count、planned_quantity、estimate_cost 与 available_balance 等。金额为十进制字符串,不用二进制浮点数处理账务。价格见实时价格,以实际预估和创建响应为准。
创建成功返回 batch_id、datas[].check_id、规范化的 datas[].target、execution_deadline_at、expires_at 及计费预估。受理成功不表示检测完成。创建时检查可用余额并预留待结算金额,按有效结果返回结算;超时、节点错误及余额不足而未接收的结果不计费。重复查询不会重复扣费。
幂等与安全重试
Idempotency-Key 可选,建议用于每次创建;支持 1–128 个字母、数字以及 . _ : -。同一账户、相同 Key、相同请求返回原批次;相同 Key 配不同请求返回 40901。创建超时、受理状态不明时复用原 Key 和原请求体,不要生成新 Key 盲目重发。
40902 表示同一创建仍在处理中,稍后用原 Key 重试。42900 时遵守 Retry-After。幂等记录随批次保留 24 小时,过期后复用 Key 会视为新请求;调用方仍应持久保存业务请求与批次的关联。
查询与结果分页
curl -X POST 'https://api.weavebit.com/v2/task/result' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{"batch_id":"BATCH_ID_FROM_CREATE","page":1,"page_size":200}'
page 默认为 1,page_size 默认及最大值为 200 个目标。按照 pagination.page、page_size、total、pages 读取所有页;分页只影响 datas,batch_status 和最终 billing 表达整个批次。需要某个目标时,在批次返回列表中按 check_id 匹配。
batch_status 与 datas[].status 使用 pending、running、completed 表达执行进度。completed 中仍可能包含超时或无法判定。非 DNS 污染方法的目标结果位于 datas[].results[],每项包含节点代码、名称及 result;DNS 污染目标通过 datas[].result 返回判定,不依赖所选节点列表。
基础方法读取 status 及对应观测字段;DNS 污染读取 result_code、status 和 a。GFW 全量的单节点 result 包含三个同名维度对象与 overall_result。0、1、null 必须分别保存和处理,不得将 null 转成正常或封锁。完整语义见结果文档。
执行期限与结果保存
批次最长执行六小时。到 execution_deadline_at 尚未返回的项目进入最终超时状态,不计费。目标与结果在创建后二十四小时到期清理,不是完成后再保留二十四小时。两种时间均为 UTC ISO 8601。
在 expires_at 前保存需要的结果,并在任务进行期间定期查询。Console 监控历史与 API 临时批次是不同的数据生命周期,不要用监控页面的历史保留时间推断 API 保留期限。
错误处理
| code | 含义 | 调用方处理 |
|---|---|---|
40000 |
请求格式错误 | 检查 JSON 与必填字段 |
40001 |
不支持的检测方法 | 核对 check_type |
40002 |
无效目标 | 检查域名、IP、端口及方法参数 |
40003 |
无效节点选择 | 重新获取节点并检查 nodes |
40004 |
超过限制 | 拆分目标或减少节点选择 |
40100 |
未认证 | 检查账户 Key,不自动无限重试 |
40201 |
可用余额不足 | 查询余额并处理未结算预留 |
40401 |
任务不存在 | 检查账户、ID 与保留期限 |
40901 |
幂等请求冲突 | 保持原请求,新的业务请求使用新 Key |
40902 |
幂等创建正在处理 | 稍后使用原 Key 重试 |
41300 |
请求体过大 | 减少本次请求内容 |
42900 |
频率限制 | 遵守 Retry-After,使用有上限的退避 |
50000 |
内部错误 | 有限重试;创建保持幂等 |
50301 |
账户有待结算金额 | 稍后重试 |
协议状态中的 NODE_TIMEOUT、NODE_ERROR、INVALID_RESULT 和 UNKNOWN 等与 API 业务错误码不是同一层。HTTP/TLS 超时、EOF 或握手错误也不能直接改写为封锁结论。
API v1 同步单域名检测
API v1 的正式地址为 https://api.weavebit.com/v1/task/pollute,仅提供同步单域名 DNS 污染检测。它与 v2 使用同一个账户 API Key,但请求采用表单字段 key、host,不要把 v2 JSON 请求直接发到 v1。
curl -X POST 'https://api.weavebit.com/v1/task/pollute' \
-H 'Accept: application/json' \
-H 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'key=YOUR_API_KEY' \
--data-urlencode 'host=example.com'
先检查 error_code 与 error_msg;成功响应的 result=0 表示未报告 DNS 污染,1 表示报告污染,-1 表示暂未获得有效结果。同步表示同一请求内等待结果,不承诺固定时长。它不是批量接口;批量、并发或其他方法优先使用 v2。账户密钥、余额和 API Explorer 在 Console 中管理。