本文档属于 Cloud WAF — 企业 Web 防护管理平台
CLI 工具:zcloud· 5 大模块:guard / sys / analytics / cli_release / auth
完整 API 索引:/api/openapi.json · 文档地图:/sitemap.xml · AI 速读:/llms.txt
API 文档
商业级 REST API 文档 · 57 个 endpoint · 80+ 图表数据接口(chart-key)· 双通道鉴权
适用对象:客户对接工程师、SRE、SaaS 集成商、AI agent
阅读顺序:先看 §0 总体约定 → §1 鉴权 → 再按业务模块跳转
目录
必读
公开接口(无需鉴权)
业务接口(双通道鉴权)
- §4 系统管理
- 4.1 用户管理 —
/api/sys/users - 4.2 API Key 管理 —
/api/sys/apikeys - 4.3 权限树 —
/api/sys/permissions/tree
- 4.1 用户管理 —
- §5 Guard 资源管理
- 5.1 域名 —
/api/guard/domains - 5.2 证书 —
/api/guard/certs - 5.3 策略 —
/api/guard/policies - 5.4 CC 规则 —
/api/guard/policies/{id}/cc/rules - 5.5 ACL 规则 —
/api/guard/policies/{id}/acl/rules - 5.6 黑白名单 —
/api/guard/bwlist - 5.7 IP 转发 —
/api/guard/forwards - 5.8 调度管理 —
/api/guard/schedules - 5.9 WAF 规则 —
/api/guard/waf/rules
- 5.1 域名 —
套餐目录
- §7 套餐目录(Plan) — 只读对外:list · describe;admin 操作不在此范围
节点运维
- §8 节点安装 / 升级(Node Install) — artifacts · commands · upgrades · jobs · tokens + 安装机侧 script/package/env/report
Analytics 统计分析(74 chart-key · 单一形状契约)
- §6.0 本章统一调用约定 — 5 字段契约 / render_hint 8 词白名单
- §6.1 术语表 · §6.2 跨页 Batch · §6.3 单图 GET 调用入口
- §6.4 总览页面 Overview · 8 chart-key
- §6.5 访问分析页面 Access · 10 chart-key
- §6.6 防护分析页面 Protect · 12 chart-key(WAF / CC / DDoS)
- §6.7 AI 识别页面 · 6 chart-key
- §6.8 主动防护 / Bot 页面 · 10 chart-key
- §6.9 告警统计页面 Alert · 5 chart-key
- §6.10 业务健康 Health · 7 chart-key
- §6.11 平台运维 Ops · 8 chart-key
- §6.12 处置闭环 Closure · 4 chart-key
- §6.13 缓存收益 Cache · 4 chart-key
- §6.14 原始日志 Logs — 非 chart endpoint
- §6.15 报表中心 Reports — 非 chart endpoint
- §6.16 CLI 对应关系 — 30 cobra 命令映射
参考
- §A 通用查询参数 — window / stime / etime / site_id / domain_id / target_user_id / compare / top / order
- §B 可视化建议总表 — B.1 render_hint 速查 · B.2 数据形态速查
- §C 相关文档
完整 OpenAPI: /api/openapi.json · AI 速读: /llms.txt · 错误码: /docs/errors · CLI: /docs/cli · 权限: /docs/permissions
§0 总体约定
Cloud WAF 后端基于 Gin 实现的 RESTful 服务。
0.1 基础协议
| 项目 | 值 |
|---|---|
| 协议 | HTTPS(推荐)/ HTTP |
| 数据格式 | 请求与响应均为 application/json(特例:POST /api/guard/certs 仍是 JSON,PEM 走字符串字段;导出/下载接口返回 text/csv、application/pdf 等) |
| 字符集 | UTF-8 |
| 路径前缀 | 所有业务 API 都挂在 /api/ 下 |
| 时间格式 | Unix 毫秒时间戳(int64),不是 ISO 字符串 |
| 国际化 | Accept-Language: zh-CN 或 en-US,影响错误消息和权限名称 |
0.2 统一响应信封
任何 JSON 响应都遵循下面三段结构:
{
"code": 0,
"message": "ok",
"data": { /* 业务载荷,类型依接口而定 */ }
}
| 字段 | 类型 | 含义 |
|---|---|---|
code |
number | 0=成功;非 0 = 业务错误码 |
message |
string | 错误描述(受 Accept-Language 影响) |
data |
any | 业务数据;列表接口为 { list, total, page, size } |
特例:导出文件下载接口(
POST /api/analytics/overview/export、GET /api/analytics/reports/:id/download、POST /api/analytics/logs/export)直接返回二进制流或 CSV/JSON 原文,不包裹信封。
0.3 HTTP 状态码
| 状态码 | 何时出现 |
|---|---|
| 200 | 业务成功(仍需检查 code) |
| 201 | 资源创建成功 |
| 400 | 入参错误(参数缺失、格式非法、超出范围) |
| 401 | 未登录、token 过期、API Key 已吊销 |
| 403 | 已登录但权限不足 / 跨 OEM 越权(参见 权限矩阵) |
| 404 | 资源不存在或不在可见范围 |
| 429 | 限流(默认每 Key 每秒 100 请求) |
| 5xx | 服务端异常 |
0.4 列表接口分页约定
所有列表接口统一使用 page + size(不是 page_size):
| 字段 | 类型 | 默认 | 范围 |
|---|---|---|---|
page |
int | 1 |
≥ 1 |
size |
int | 20 |
1 - 100 |
响应:
{
"code": 0,
"data": {
"list": [ /* ... */ ],
"total": 42,
"page": 1,
"size": 20
}
}
0.5 跨模块设计标记(D*)
文档中少量 D* 标记来自跨模块设计决策,用于提醒对接方不要使用不存在或语义错误的字段:
| 标记 | 含义 |
|---|---|
| D4 | percentile / p50 / p95 / p99 不作为通用字段暴露;仅时间窗 ≤ 24h 时走实时 ES percentile 计算 |
| D7 | 报表模板枚举为闭集,超出枚举的模板名不可调用 |
| D8 | 缓存价值字段以 total_cache_* 为准,不存在 cache_count / cache_bytes / cache_hit 这类单字段 |
| D10 | 告警/风险处置闭环字段以 process_uid / process_time / status / level 为准,不使用旧字段 handle_user / handle_time / risk_score / alert_status |
0.6 三类读者的阅读路径
| 读者 | 入口 | 优先用 |
|---|---|---|
| 人类对接工程师 | 本文档 + 快速上手 | curl / Postman 调单接口 |
| 脚本 / CI / 第三方系统 | 本文档 + API Key 管理 | API Key + 受限 scopes |
| 机器 / AI agent | /api/openapi.json / /llms.txt / /llms-full.txt |
OpenAPI v3 schema |
§1 鉴权(先读)
Cloud WAF 当前支持两条认证通道,同一请求只能选其中一种:
| 场景 | 请求头 | 适用对象 | 说明 |
|---|---|---|---|
| 人工登录 / Web 控制台 / CLI 交互登录 | Authorization: Bearer <token> |
人 | token 由 POST /api/auth/login 颁发,会过期,适合短期会话 |
| 脚本 / CI / 第三方系统集成 | Authorization: ApiKey zck_<prefix>.<secret> |
机器调用 | API Key 明文仅签发时返回一次,适合长期自动化对接 |
公开接口(无需鉴权)只有 4 个:
GET /api/cli/versionGET /api/cli/install.shGET /api/cli/download/{filename}GET /api/cli/checksums.txtPOST /api/auth/login
其它所有接口都必须携带上述任一认证头。下面各接口示例默认使用 Bearer;如改用 API Key,只需把请求头替换为 Authorization: ApiKey zck_<prefix>.<secret>,并确保该 Key 的 scopes 覆盖接口所需权限。
1.1 API Key 权限规则
effective_perms = user.RBAC ∩ key.scope
API Key 的权限不会超过签发用户当前的 RBAC;scope 只能收窄,不能放大。中间件认证通过后会注入与会话通道一致的 user_id / role_id 上下文,下游 RBAC/OEM 隔离保持一致。
安全约束:
- 明文 API Key 仅在签发响应里出现一次,落库零明文(
key_hash是 bcrypt 摘要) - 用户被锁定或删除后,其名下 API Key 自动失效
scopes非空时,请求权限必须精确命中其中之一;为空表示完整继承当前 RBAC- 跨 OEM 越权由中间件拦截:
api_keys.oem_id与请求 hostname 不一致时直接 403 - 可选 IP 白名单
allowed_ip_cidrs:非空时只放行命中 CIDR 的请求
API Key 管理接口的完整说明见 §4.2。
§2 CLI 发布(公开接口)
供 zcloud CLI 自更新与一键安装使用,无需鉴权。
GET /api/cli/version — 查询 CLI 最新版本
用途:客户端启动时自检版本;安装脚本 /api/cli/install.sh 内部依赖此接口决定下载哪个二进制。
鉴权:无(公开)
输入参数:无
输出字段:
| 字段 | 类型 | 说明 |
|---|---|---|
data.version |
string | 形如 v0.1.0-31,对齐 git tag |
data.binaries[] |
array | 4 个 os/arch 组合的下载地址 |
data.binaries[].os |
string | linux / darwin |
data.binaries[].arch |
string | amd64 / arm64 |
data.binaries[].download_url |
string | 拼接服务地址即可下载 |
可视化建议:纯文本展示(版本徽章),不适合图表。前端可用作"系统设置 - CLI 版本"页面的 KPI 数字卡。
示例响应:
{
"code": 0,
"message": "ok",
"data": {
"version": "v0.1.0-31",
"binaries": [
{ "os": "linux", "arch": "amd64", "download_url": "/api/cli/download/linux-amd64" },
{ "os": "linux", "arch": "arm64", "download_url": "/api/cli/download/linux-arm64" },
{ "os": "darwin", "arch": "amd64", "download_url": "/api/cli/download/darwin-amd64" },
{ "os": "darwin", "arch": "arm64", "download_url": "/api/cli/download/darwin-arm64" }
]
}
}
GET /api/cli/install.sh — 一键安装脚本
用途:在 Linux/macOS 上一行命令完成 CLI 安装。返回 text/x-shellscript,可直接 curl ... | sh。
鉴权:无(公开)
输入参数:无
输出字段:纯 shell 脚本文本,不走 JSON 信封。
可视化建议:不适合图表,作为代码片段展示。
示例:
curl -fsSL https://waf.example.com/api/cli/install.sh | sh
GET /api/cli/download/{filename} — 下载指定二进制
用途:拉取特定平台的 zcloud 二进制(已签名)。filename 取自 /api/cli/version 返回的 download_url 的最后一段,如 linux-amd64。
鉴权:无(公开)
输入参数:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
filename |
path | 是 | linux-amd64 / linux-arm64 / darwin-amd64 / darwin-arm64 其一 |
输出字段:二进制流(application/octet-stream)。
可视化建议:不适合图表。
GET /api/cli/checksums.txt — 二进制校验和
用途:配合 /api/cli/download/* 做 SHA256 完整性校验,安装脚本会先 fetch 这个文件再下载二进制。
鉴权:无(公开)
输入参数:无
输出字段:纯文本 text/plain,每行一个 <sha256> <filename>。
可视化建议:不适合图表。
§3 用户认证
POST /api/auth/login — 登录
用途:用用户名 + 密码换取一个会话 token。Web 控制台、CLI 交互式登录、移动端均走此接口。
鉴权:无(公开)
输入参数(请求体):
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
username |
string | 是 | 用户名 |
password |
string | 是 | 密码(前端 base64 编码后传入,后端 decode 后再 bcrypt 比对,兼容老系统) |
输出字段:
| 字段 | 类型 | 说明 |
|---|---|---|
data.token |
string | 32 位会话 token,用于后续 Authorization: Bearer <token> |
data.user_id |
string | 用户唯一 ID |
data.user_name |
string | 用户名 |
data.nick_name |
string | 显示名 |
data.need_change_password |
bool | true 表示首次登录需强制改密码 |
可视化建议:登录响应不直接做图,但 need_change_password=true 时前端应跳转改密页。
示例请求:
curl -X POST https://waf.example.com/api/auth/login \
-H 'Content-Type: application/json' \
-d '{"username":"admin","password":"'$(echo -n 'your_password' | base64)'"}'
示例响应:
{
"code": 0,
"message": "ok",
"data": {
"token": "550e8400-e29b-41d4-a716-446655440000",
"user_id": "u-admin",
"user_name": "admin",
"nick_name": "系统管理员",
"need_change_password": false
}
}
常见误用:
- 直接传明文密码 → 后端 base64 decode 失败,统一返回"用户名或密码错误",无法定位真实原因
- token 在多端复用 → 注销时可能影响其它端,建议每端独立登录
POST /api/auth/logout — 注销
用途:主动失效当前 Bearer token;再次请求该 token 返回 401。
鉴权:Bearer <token>(API Key 通道无 logout 概念,吊销走 DELETE /api/sys/api-keys/:id)
输入参数:无
输出字段:data 为 null。
可视化建议:不适合图表。
示例请求:
curl -X POST https://waf.example.com/api/auth/logout \
-H "Authorization: Bearer $TOKEN"
§4 系统管理
4.1 用户管理
适用场景:在"系统设置 - 用户管理"页面增删改查用户。所有用户接口都受 OEM 隔离,跨 OEM 操作会返回 403。
GET /api/sys/users — 用户列表(分页)
用途:在"用户管理"页面渲染用户表格,支持关键字模糊搜索 + 分页。
鉴权:sys.user.list
输入参数:
| 字段 | 类型 | 必填 | 取值/示例 | 说明 |
|---|---|---|---|---|
page |
int | 否 | 1 |
页码,从 1 起 |
size |
int | 否 | 20 |
每页条数,1-100 |
keyword |
string | 否 | admin |
用户名/显示名模糊搜索 |
输出字段(data.list[]):
| 字段 | 类型 | 说明 |
|---|---|---|
user_id |
string | 用户唯一 ID |
user_name |
string | 登录用户名 |
nick_name |
string | 显示名 |
email |
string | 邮箱 |
mobile |
string | 手机号 |
locked |
int | 0=正常,非 0=锁定 |
role_ids |
int64[] | 角色 ID 列表(可多角色) |
roles[] |
array | 角色摘要 {role_id, name, level} |
ctime |
int64 | 创建时间,Unix 毫秒 |
可视化建议:表格展示。locked 列建议用徽章(绿/红);roles 用 chip 标签。
示例请求:
curl -H "Authorization: Bearer $TOKEN" \
"https://waf.example.com/api/sys/users?page=1&size=20&keyword=admin"
示例响应:
{
"code": 0,
"message": "ok",
"data": {
"list": [
{
"user_id": "u-001",
"user_name": "admin",
"nick_name": "系统管理员",
"email": "admin@example.com",
"mobile": "",
"locked": 0,
"role_ids": [1],
"roles": [{ "role_id": 1, "name": "超级管理员", "level": 1 }],
"ctime": 1714521600000
}
],
"total": 42,
"page": 1,
"size": 20
}
}
常见误用:
- 把
role_ids当成单值字段 → 用户可有多角色,必须按数组处理 - 用
level做权限阈值判断 →level是展示字段(业务层级),权限阈值用role_id(参见 pitfall_role_level_vs_role_id)
POST /api/sys/users — 创建用户
用途:在"用户管理"页面提交"新建用户"表单。
鉴权:sys.user.create
输入参数(请求体):
| 字段 | 类型 | 必填 | 取值/示例 | 说明 |
|---|---|---|---|---|
user_name |
string | 是 | u1 |
2-255 字符 |
password |
string | 是 | InitPassw0rd! |
6-72 字符(bcrypt 上限) |
nick_name |
string | 否 | 运维 A |
≤ 100 字符 |
email |
string | 否 | u1@x.com |
标准邮箱格式 |
mobile |
string | 否 | 13800138000 |
≤ 20 字符 |
comment |
string | 否 | 值班同事 |
备注 |
输出字段:返回新建用户对象,结构同列表项。
可视化建议:不适合图表,是一次性写操作;前端应在成功后刷新用户列表。
示例请求:
curl -X POST https://waf.example.com/api/sys/users \
-H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{"user_name":"u1","password":"InitPassw0rd!","nick_name":"运维 A","email":"u1@example.com"}'
DELETE /api/sys/users/{id} — 删除用户
用途:用户管理页面"删除"按钮的后端接口。删除会级联清理会话、API Key、角色绑定。
鉴权:sys.user.delete
输入参数:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id |
path | 是 | 用户 user_id |
输出字段:data 为 null。
可视化建议:不适合图表。
PUT /api/sys/users/{id}/password — 重置密码
用途:管理员替用户重置密码。被重置用户下次登录后强制改密码。
鉴权:sys.user.resetpwd
输入参数:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id |
path | 是 | 用户 user_id |
password |
string | 是 | 新密码(明文,6-72 字符;后端自动 bcrypt) |
输出字段:data 为 null。
可视化建议:不适合图表。
示例请求:
curl -X PUT https://waf.example.com/api/sys/users/u-001/password \
-H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{"password":"NewPassw0rd!"}'
常见误用:
- 期望前端做 base64 编码 → 此接口直接传明文,与登录接口不同(登录接口 base64 是历史兼容)
4.2 API Key 管理
适用场景:在"系统设置 - API Key"页面发放/回收脚本调用凭证。配合
/api/sys/api-keys/:id/logs|stats|audit-actions做调用审计。
POST /api/sys/api-keys — 签发新 API Key
用途:为脚本/CI/第三方系统签发一条机器调用凭证。明文 api_key 字段仅此一次返回,前端必须立即让用户复制保存。
鉴权:sys.apikey.create
输入参数(请求体):
| 字段 | 类型 | 必填 | 取值/示例 | 说明 |
|---|---|---|---|---|
name |
string | 是 | 生产对接 |
≤ 100 字符,用于审计识别 |
scopes |
string[] | 否 | ["guard.domain.list"] |
权限 full key 列表;空数组 = 完整继承签发用户当前 RBAC |
expires_in_days |
int | 否 | 90 |
过期天数,默认 90,最大 365 |
allowed_ip_cidrs |
string[] | 否 | ["203.0.113.0/24"] |
E14 IP 白名单 CIDR;为空表示不限制来源 IP |
输出字段:
| 字段 | 类型 | 说明 |
|---|---|---|
data.key_id |
string | API Key 唯一 ID(吊销/查日志用此 ID) |
data.name |
string | 与请求一致 |
data.api_key |
string | 完整明文 prefix.secret,仅此一次返回 |
data.prefix |
string | 形如 zck_abc12345,可写入日志 |
data.last4 |
string | secret 末 4 位,前端用于"我刚签的那条"识别 |
data.expires_at |
int64 | 过期时间,Unix 毫秒 |
错误码:
1052scope 超出用户 RBAC 边界1054expires_in_days > 3651055name缺失
可视化建议:签发响应是一次性写操作,建议前端用模态框 + 一次性复制按钮 + 遮码展示明文(参考行业惯例 GitHub/Stripe)。
示例请求:
curl -X POST https://waf.example.com/api/sys/api-keys \
-H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{"name":"生产对接","scopes":["guard.domain.list"],"expires_in_days":90}'
示例响应:
{
"code": 0,
"data": {
"key_id": "8f21c0c5-55ae-4cbd-a60a-8e64a6e2b1d0",
"name": "生产对接",
"api_key": "zck_abc12345.A1b2C3d4E5f6G7h8I9j0K1L2M3n4O5p6Q7r8S9t0",
"prefix": "zck_abc12345",
"last4": "5t0",
"expires_at": 1732982400000
}
}
常见误用:
- 把
api_key字段存数据库 → 应只存key_id+prefix,明文交给业务方一次性 scopes列空数组以为是无权限 → 空数组实际代表完整继承当前 RBAC,要明确收窄就传具体权限 key
GET /api/sys/api-keys — 查询 API Key 列表
用途:在 API Key 管理页面展示当前用户/OEM 内的 Key 清单与状态。
鉴权:sys.apikey.list
输入参数:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
page |
int | 否 | 默认 1 |
size |
int | 否 | 默认 20,最大 100 |
输出字段(data.list[]):
| 字段 | 类型 | 说明 |
|---|---|---|
key_id |
string | API Key 唯一 ID |
name |
string | 名称 |
prefix |
string | zck_xxx 前缀 |
last4 |
string | secret 末 4 位 |
user_id |
string | 持有人 |
oem_id |
string | OEM 隔离边界 |
scopes |
string[] | 限定权限列表 |
allowed_ip_cidrs |
string[] | E14 IP 白名单 |
status |
int | 1=active,2=revoked |
expires_at |
int64 | 过期时间 |
last_used_at |
int64 | 最近调用时间;从未用为 0 |
last_used_ip |
string | 最近调用 IP;从未用为 "" |
ctime |
int64 | 签发时间 |
可见范围:
- 普通用户(
role_id ≥ 10):只看自己签发的 - 平台级用户(
role_id < 10:超管/运维/审计员):看本 OEM 全部
可视化建议:表格展示。status 用徽章(绿=active/灰=revoked),expires_at 即将到期(< 7d)建议高亮。配合 /stats 接口可做柱状图"调用量 TOP 5 Key"。
示例请求:
curl -H "Authorization: Bearer $TOKEN" \
"https://waf.example.com/api/sys/api-keys?page=1&size=20"
DELETE /api/sys/api-keys/{id} — 吊销 API Key
用途:软吊销(status → revoked),保留审计痕迹。中间件认证时 status != active 直接拒绝。
鉴权:sys.apikey.delete
输入参数:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id |
path | 是 | API Key key_id |
输出字段:data 为 null。
幂等性:重复吊销返回 200,前端反复操作不报错。
可操作范围:
- 普通用户:只能吊销自己签发的
- 平台级用户:可吊销本 OEM 内任意 key(管理止损用)
错误码:1051 API Key 不存在或不在可见范围。
可视化建议:不适合图表;前端"吊销"按钮触发,建议加二次确认对话框。
示例请求(用 API Key 调用):
curl -X DELETE https://waf.example.com/api/sys/api-keys/8f21c0c5-55ae-4cbd-a60a-8e64a6e2b1d0 \
-H "Authorization: ApiKey zck_abc12345.A1b2C3d4..."
GET /api/sys/api-keys/{id}/logs — 查询某 Key 的调用流水(E12)
用途:审计某条 API Key 的调用历史。返回该 Key 在审计表 api_key_audit_logs 中的事件列表。
鉴权:sys.apikey.logs
输入参数:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id |
path | 是 | API Key key_id |
event |
string | 否 | call(默认,调用流水)/ manage(管理操作) |
page |
int | 否 | 默认 1 |
size |
int | 否 | 默认 20,最大 100 |
输出字段(每条记录):
| 字段 | 类型 | 说明 |
|---|---|---|
id |
int | 自增主键 |
event_type |
string | call / manage |
key_id |
string | 关联的 API Key ID |
user_id |
string | 操作主体(call=key 持有人;manage=操作人) |
auth_mode |
string | apikey / session,记录请求通过的认证通道 |
action |
string | call=<METHOD> <PATH>;manage=create / revoke / renew / revoke-all |
status_code |
int | HTTP 响应状态码(call 类型有效) |
biz_code |
int | 业务错码(0 = 成功;call 类型有效) |
client_ip |
string | 客户端 IP |
user_agent |
string | UA(≤ 255 字符,超长截断) |
extra |
string | JSON 字符串,承载续期 / 批量动作等结构化扩展字段 |
ctime |
int | Unix 毫秒时间戳 |
可视化建议:
- 推荐图表:表格 + 时序折线图(按 ctime 聚合调用次数)
- 派生指标:成功率柱状图(按 status_code 拆分 2xx/4xx/5xx)
可见范围:
- 普通用户:仅可查询自己签发的 Key
- 平台级用户:可查询本 OEM 内任意 Key(超管全库)
错误码:1051 API Key 不存在或不在可见范围。
GET /api/sys/api-keys/{id}/stats — 查询某 Key 的聚合统计
用途:在 API Key 详情页展示该 Key 的调用聚合 KPI(总次数、成功率、QPS、TOP 接口)。仅基于 event_type=call 的记录。
鉴权:sys.apikey.stats
输入参数:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id |
path | 是 | API Key key_id |
since |
string/int | 否 | 聚合窗口起点;支持 24h / 7d / 30m 相对值,或纯整数 = 毫秒时间戳;留空 = 全量历史 |
输出字段:
| 字段 | 类型 | 说明 |
|---|---|---|
total_calls |
int | 窗口内总调用次数 |
success |
int | 200 ≤ status_code < 400 的次数 |
client_err |
int | 400 ≤ status_code < 500 的次数 |
server_err |
int | status_code ≥ 500 的次数 |
top_endpoints |
array | 调用次数 Top 5 的 action({action, count},按次数降序) |
last_1h_qps |
float | 最近 1 小时 QPS(次数 / 3600) |
可视化建议:
- 推荐图表:KPI 数字卡(4 个:total_calls / 成功率 / QPS / 错误数)+ 横向 bar 图(top_endpoints)
- 派生指标:饼图(success / client_err / server_err 三段占比)
错误码:400 since 解析失败;1051 API Key 不存在或不在可见范围。
示例请求:
curl -H "Authorization: Bearer $TOKEN" \
"https://waf.example.com/api/sys/api-keys/8f21c0c5-55ae-4cbd-a60a-8e64a6e2b1d0/stats?since=24h"
GET /api/sys/api-keys/audit-actions — 查询管理操作流水(E13)
用途:跨 Key 的审计视图,返回 API Key 管理动作(创建 / 吊销 / 续期 / 批量吊销)的流水。
鉴权:sys.apikey.audit
输入参数:page / size,标准分页。
输出字段:与 GET /api/sys/api-keys/{id}/logs 相同;event_type 全部为 manage。
可见范围:
- 普通用户:只看自己作为操作人的记录(
user_id = currentUserID) - 平台级用户:本 OEM 全部(超管全库)
可视化建议:
- 推荐图表:表格(按 ctime 倒序)
- 派生指标:按 action 聚合的柱状图(create / revoke / renew / revoke-all 计数)
4.3 权限树
GET /api/sys/permissions/tree — 权限树
用途:返回当前 OEM 下的完整权限树(含模块/资源/动作三层 + i18n 名)。前端"角色权限"页用此渲染勾选树;签发 API Key 选 scope 时也用同一颗树。
鉴权:登录态(无具体权限要求)
输入参数:可附加 Accept-Language: en-US 切换权限名语言。
输出字段(节选,data[]):
| 字段 | 类型 | 说明 |
|---|---|---|
module |
string | 模块名,如 guard / sys / analytics |
resources[] |
array | 该模块下的资源列表 |
resources[].prefix |
string | 资源前缀,如 guard.domain |
resources[].name |
string | 资源 i18n 显示名 |
resources[].actions[] |
array | 该资源的动作列表 |
resources[].actions[].key |
string | 动作短 key,如 list / create |
resources[].actions[].name |
string | 动作 i18n 显示名 |
resources[].actions[].full_key |
string | 完整权限 key,如 guard.domain.list |
可视化建议:
- 推荐图表:三层树(n-tree / el-tree),module → resource → action
- 复用场景:API Key scope 选择器、角色权限分配勾选器
示例响应(节选):
{
"code": 0,
"data": [
{
"module": "guard",
"resources": [
{
"prefix": "guard.domain",
"name": "域名",
"actions": [
{ "key": "list", "name": "列表", "full_key": "guard.domain.list" },
{ "key": "view", "name": "查看", "full_key": "guard.domain.view" },
{ "key": "create", "name": "创建", "full_key": "guard.domain.create" }
]
}
]
}
]
}
§5 Guard 资源管理
📦 Guard 资源管理 · 30 个 endpoint · 用于配置防护对象(域名/证书/策略/CC&ACL 规则/名单/转发/调度/WAF 规则),是 WAF 防护能力的"配置面"
完整 schema 见/api/openapi.json,本节给出对接最关键的字段名、枚举与典型踩坑点。
5.1 域名 /api/guard/domains
域名是 Guard 的核心资源——所有防护策略、证书绑定、统计聚合都以 domain_id 为锚点。
GET /api/guard/domains — 域名列表
用途:在"防护管理 - 域名"页面渲染域名表格,按审核状态筛选 + 关键字搜索。
鉴权:guard.domain.list
输入参数:
| 字段 | 类型 | 必填 | 取值/示例 | 说明 |
|---|---|---|---|---|
page |
int | 否 | 1 |
页码 |
size |
int | 否 | 20 |
每页条数,1-100(不是 page_size) |
keyword |
string | 否 | api.example |
模糊搜索 domain 或 asset_name |
audit_status |
int | 否 | 4 |
1=未审核 2=审核中 3=未通过 4=通过 |
输出字段(data.list[] 即 DomainVO):
| 字段 | 类型 | 说明 |
|---|---|---|
domain_id |
string | 域名唯一 ID |
domain |
string | 域名本身,如 api.example.com |
asset_name |
string | 资产备注名 |
user_id |
string | 归属用户 UUID(保留兼容老平台) |
user_name |
string | 归属用户名(P1.3 新增,来源 cloud sys.users) |
policy_id |
string | 关联策略 ID |
cname |
string | 后端为该域名分配的 CNAME |
auto_cert |
bool | 是否启用自动签发证书 |
mode |
int32 | 接入模式(1=反代等,参见运维文档) |
audit_status |
int32 | 1=未审核 2=审核中 3=未通过 4=通过 |
switches |
map<string,int32> | 保护开关,key 取自 waf/cc/acl/bot/cache,1=开 0=关 |
ctime / utime |
int64 | 创建/更新时间 |
可视化建议:
- 推荐图表:表格(主图)+ 顶部 KPI 卡片(总数 / 已通过 / 待审核)+
switches用 chip 方阵渲染开关状态 - 派生指标:饼图(
audit_status4 状态占比)
示例请求:
curl -H "Authorization: ApiKey $ZCLOUD_API_KEY" \
"https://waf.example.com/api/guard/domains?page=1&size=20&audit_status=4"
示例响应:
{
"code": 0,
"data": {
"list": [
{
"domain_id": "d_8a3b1c",
"domain": "api.example.com",
"asset_name": "线上 API 网关",
"user_id": "u_abc",
"policy_id": "p_default",
"cname": "api.example.com.cname.zcloud.io",
"auto_cert": false,
"mode": 1,
"audit_status": 4,
"switches": { "waf": 1, "cc": 1, "acl": 1, "bot": 0, "cache": 1 },
"ctime": 1714521600000,
"utime": 1714608000000
}
],
"total": 8,
"page": 1,
"size": 20
}
}
常见误用:
- 用
page_size分页 → 实际是size,传page_size会被忽略 - 期望返回
protection_enabled/current_cert_id/origin_addr→ 这些字段不存在;保护开关在switchesmap 里,证书绑定走/api/guard/certs/:id/domains反查
POST /api/guard/domains — 创建域名
用途:在"添加域名"表单提交后调用,创建一条新的防护域名。
鉴权:guard.domain.create
输入参数(请求体 DomainCreateReq):
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
domain |
string | 是 | 域名本身,如 api.example.com |
asset_name |
string | 否 | 资产备注名 |
policy_id |
string | 否 | 绑定策略;不传走默认 |
重要:
domain是唯一必填项;证书绑定走POST /api/guard/certs/:id/bind,不要通过 create-domain 设置;origin_addr/port/cert_id字段不存在。
输出字段:返回 DomainVO(结构同列表项),含分配的 domain_id 和 cname。
可视化建议:不适合图表。建议创建成功后立即跳转域名详情页或刷新列表。
GET /api/guard/domains/{id} — 域名详情
用途:进入域名详情页时拉单条详情。
鉴权:guard.domain.view
输入参数:path id = domain_id。
输出字段:DomainVO,与列表项完全一致。
可视化建议:表单展示。switches 渲染为开关组;audit_status 用徽章。
PUT /api/guard/domains/{id} — 更新域名
用途:编辑域名的资产名、策略绑定、自动证书等可变字段。
鉴权:guard.domain.edit
输入参数(请求体 DomainUpdateReq):
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
asset_name |
string | 否 | 资产备注名 |
policy_id |
string | 否 | 切换策略 |
auto_cert |
bool | 否 | 切换自动签发开关 |
mode |
int32 | 否 | 接入模式 |
输出字段:返回更新后的 DomainVO。
可视化建议:不适合图表。
DELETE /api/guard/domains/{id} — 删除域名
用途:从防护列表中移除域名。删除会级联清理 settings、证书绑定、统计快照。
鉴权:guard.domain.delete
输入参数:path id = domain_id。
输出字段:data 为 null。
可视化建议:不适合图表。建议删除前二次确认,提示"会清理统计与绑定"。
GET /api/guard/domains/{id}/settings — 域名设置查询
用途:在域名详情页"高级设置"标签下展示当前生效的 settings(保护模块开关、缓存策略、CC 限速等)。
鉴权:guard.domain.view
输入参数:path id = domain_id。
输出字段:
| 字段 | 类型 | 说明 |
|---|---|---|
data.settings |
map<string,string> | key 取自后端 settings.* 字典,典型 waf/cc/acl/bot/cache,value 是 stringified 配置 JSON |
可视化建议:表单展示,每个 key 一行配置卡片。
PUT /api/guard/domains/{id}/settings — 域名设置更新
用途:修改域名的 settings map。
鉴权:guard.domain.edit
输入参数(请求体 DomainSettingsUpdateReq):
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
settings |
map<string,string> | 是 | key 必须取自 GET /settings 返回的 settings.* 键名;非法 key 后端会拒绝 |
输出字段:data 为 null,调用方应紧接调用 GET 拉新值。
可视化建议:不适合图表。
常见误用:
- 把顶层布尔字段当 settings 传 → settings value 是 stringified JSON,不是 bool
- 自创不存在的 key → 后端按白名单校验,未知 key 返回 400
5.2 证书 /api/guard/certs
证书管理走"上传 PEM 文本 → 绑定域名"两步流程;Content-Type 是 application/json,不是 multipart/form-data。
GET /api/guard/certs — 证书列表
用途:"防护管理 - 证书"页面表格。
鉴权:guard.cert.list
输入参数:page / size / keyword(搜索 name/common_name)。
输出字段(data.list[] = CertVO):
| 字段 | 类型 | 说明 |
|---|---|---|
id |
uint64 | 证书唯一 ID |
name |
string | 自定义名称 |
user_name |
string | 归属用户名(P1.3 替换原 user_id,来源 cloud sys.users) |
certificate_type |
int32 | 证书类型枚举 |
common_name |
string | 证书 CN |
issuer |
string | 颁发者 |
expired_at |
int64 | 到期时间,Unix 毫秒 |
auto_cert |
bool | 是否自动续期 |
ctime / utime |
int64 | 创建/更新时间 |
不存在
bound_domains字段;要查证书绑定哪些域名,调GET /api/guard/certs/{id}/domains。
可视化建议:
- 推荐图表:表格 + 即将到期高亮(
expired_at - now < 30d染色) - 派生指标:KPI 卡(总数 / 30d 内到期数 / 已过期数);饼图(
auto_certtrue/false 占比)
POST /api/guard/certs — 上传证书
用途:上传一条 PEM 证书。客户对接最容易踩的坑就是误用 multipart/form-data,请务必用 JSON。
鉴权:guard.cert.create
安全提示:直接集成本接口时,cert / key 仍按 JSON PEM 文本传入;但不要把私钥写入 AI 对话、工单、日志或可观测埋点。若通过 Aegeon Cloud 对话助手操作证书,优先使用其"安全证书附件"上传入口:浏览器将证书/私钥上传到 Aegeon 后只在对话中保留附件引用,私钥不会进入 AI 消息内容。
输入参数(请求体 CertUploadReq,application/json):
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
name |
string | 是 | 证书名 |
cert |
string | 是 | PEM 文本字符串(含 -----BEGIN CERTIFICATE----- 头尾) |
key |
string | 是 | 私钥 PEM 文本字符串 |
sign_cert |
string | 否 | 国密签名证书 PEM(可选) |
sign_key |
string | 否 | 国密签名私钥 PEM(可选) |
输出字段:返回新建 CertVO。
可视化建议:不适合图表。前端上传组件应支持"粘贴 PEM 文本"和"读取本地文件"两种方式。
示例请求:
curl -X POST https://waf.example.com/api/guard/certs \
-H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{"name":"prod-2026","cert":"-----BEGIN CERTIFICATE-----\nMII...\n-----END CERTIFICATE-----","key":"-----BEGIN PRIVATE KEY-----\nMII...\n-----END PRIVATE KEY-----"}'
常见误用:
- 用
multipart/form-data上传文件 → 后端不支持,返回 400 cert/key字段传文件路径 → 必须是 PEM 文本字符串本身- 将私钥原文放进 AI 对话或日志 → 应使用安全附件/密钥托管路径,仅在服务端短暂解密后调用本接口
GET /api/guard/certs/{id} — 证书详情
用途:详情页展示,含完整 PEM 文本。
鉴权:guard.cert.view
输入参数:path id。
输出字段:CertDetailVO = CertVO + cert + sign_cert(PEM 文本,方便下载)。
可视化建议:表单展示。可加"下载证书"按钮(前端拼 PEM 触发下载)。
PUT /api/guard/certs/{id} — 更新证书
用途:直接替换 PEM 文本(无需先删后建)。
鉴权:guard.cert.edit
输入参数(请求体 CertUpdateReq,字段同 Upload 但全部可选):name / cert / key / sign_cert / sign_key。
输出字段:返回更新后的 CertVO。
DELETE /api/guard/certs/{id} — 删除证书
鉴权:guard.cert.delete
输入参数:path id。
输出字段:data 为 null。
副作用:删除前会自动解绑该证书绑定的所有域名。
GET /api/guard/certs/{id}/domains — 查询证书已绑定的域名
用途:在证书详情页展示"该证书正在保护哪些域名"。
鉴权:guard.cert.view
输入参数:path id。
输出字段(data[] = CertDomainVO[]):
| 字段 | 类型 | 说明 |
|---|---|---|
domain_id |
string | 域名 ID |
domain |
string | 域名 |
cert_id |
uint64 | 证书 ID(即 path id) |
ctime |
int64 | 绑定时间 |
可视化建议:表格展示。
POST /api/guard/certs/{id}/bind — 绑定证书到域名
用途:把指定证书绑到一个域名上。
鉴权:guard.cert.edit
输入参数(请求体 CertBindReq):
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
domain_id |
string | 是 | 目标域名 ID |
输出字段:data 为 null。
可视化建议:不适合图表。
DELETE /api/guard/certs/{id}/bind/{domainId} — 解绑证书与域名
用途:解除证书与某个域名的绑定关系。
鉴权:guard.cert.edit
输入参数:path id = 证书 ID;path domainId = 域名 ID。
输出字段:data 为 null。
路径:是
DELETE /bind/{domainId},不是POST /unbind。
5.3 策略 /api/guard/policies
策略是规则的容器:CC / ACL / 黑白名单 都挂在策略下。一个域名绑一个策略。
GET /api/guard/policies — 策略列表
鉴权:guard.policy.list
输入参数:page / size / keyword。
输出字段(data.list[] = PolicyVO):
| 字段 | 类型 | 说明 |
|---|---|---|
policy_id |
string | 策略 ID |
name |
string | 策略名 |
comment |
string | 备注(不是 remark) |
user_id |
string | 归属用户 UUID(保留兼容老平台) |
user_name |
string | 归属用户名(P1.3 新增,来源 cloud sys.users) |
default_main_rule_version |
string | 默认主规则版本 |
is_default |
bool | 是否系统默认策略 |
schema_id |
int64 | schema 版本 |
cc_rule_count |
int32 | 该策略下的 CC 规则数 |
bwl_rule_count |
int32 | 黑白名单规则数 |
acl_rule_count |
int32 | ACL 规则数 |
ctime / utime |
int64 | 创建/更新时间 |
可视化建议:表格 + 三个 chip(cc/bwl/acl 数量)。
POST /api/guard/policies — 创建策略
鉴权:guard.policy.create
输入参数(PolicyCreateReq):name(必填)/ comment。
输出字段:返回新建 PolicyVO。
GET /api/guard/policies/{id} — 策略详情
鉴权:guard.policy.view
输入参数:path id。
输出字段:PolicyVO。
PUT /api/guard/policies/{id} — 更新策略
鉴权:guard.policy.edit
输入参数(PolicyUpdateReq):name / comment。
输出字段:返回更新后的 PolicyVO。
DELETE /api/guard/policies/{id} — 删除策略
鉴权:guard.policy.delete
输入参数:path id。
输出字段:data 为 null。删除前需保证该策略未被任何域名引用。
5.4 CC 规则 /api/guard/policies/{id}/cc/rules
CC = HTTP 速率限制规则(Connection / Concurrency Control)。挂在策略下,按 policy_id 隔离。
GET /api/guard/policies/{id}/cc/rules — CC 规则列表
鉴权:guard.cc.list
输入参数:path id = policy_id;query page / size。
输出字段(data.list[] = CcRuleVO):
| 字段 | 类型 | 说明 |
|---|---|---|
rule_id |
int64 | 规则 ID |
name |
string | 规则名 |
describe |
string | 描述 |
matches[] |
array | 匹配条件结构(路径/方法/头部等) |
stats |
object | 统计聚合维度 |
limit |
object | 速率限制阈值 |
action |
object | 命中动作(拦截/验证码/限速等) |
stime / etime |
int64 | 生效起止时间 |
status |
int32 | 1=启用 2=禁用 |
ctime / utime |
int64 | 创建/更新时间 |
可视化建议:表格 + status 徽章。matches 太复杂建议折叠为"详情"按钮弹出。
POST /api/guard/policies/{id}/cc/rules — 创建 CC 规则
鉴权:guard.cc.create
输入参数(CcRuleCreateReq):
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
name |
string | 是 | 规则名 |
describe |
string | 否 | 描述 |
matches[] |
array | 是 | 至少 1 项匹配条件 |
stats |
object | 否 | 统计维度(IP/URI/UA 等) |
limit |
object | 是 | 速率上限 |
action |
object | 是 | 命中动作 |
stime / etime |
int64 | 否 | 生效时间窗 |
复杂结构建议先调 list 取一条样本作为模板。
输出字段:返回新建 CcRuleVO。
GET /api/guard/policies/{id}/cc/rules/{rid} — CC 规则详情
鉴权:guard.cc.view
输入参数:path id = policy_id,rid = rule_id。会校验 rule_id 是否归属当前 policy_id,跨策略读取返回 NotFound。
输出字段:CcRuleVO。
PUT /api/guard/policies/{id}/cc/rules/{rid} — 更新 CC 规则
鉴权:guard.cc.edit
输入参数:path id + rid,body 同 Create。
输出字段:返回更新后的 CcRuleVO。
DELETE /api/guard/policies/{id}/cc/rules/{rid} — 删除 CC 规则
鉴权:guard.cc.delete
输入参数:path id + rid。
输出字段:data 为 null。
PUT /api/guard/policies/{id}/cc/rules/{rid}/status — 切换 CC 规则状态
用途:在列表页用开关组件启用/禁用规则。
鉴权:guard.cc.edit
输入参数(CcRuleStatusReq):
| 字段 | 类型 | 必填 | 取值 |
|---|---|---|---|
status |
int32 | 是 | 1=启用 2=禁用 |
重要:
status是 int32 数字,不是"enabled"/"disabled"字符串。
输出字段:data 为 null。
示例请求:
curl -X PUT https://waf.example.com/api/guard/policies/p_default/cc/rules/12345/status \
-H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{"status":1}'
5.5 ACL 规则 /api/guard/policies/{id}/acl/rules
ACL = 访问控制列表(基于 IP / Header / URI 的放行/拦截)。结构与 CC 规则相似但没有
priority字段。
GET /api/guard/policies/{id}/acl/rules — ACL 规则列表
鉴权:guard.acl.list
输入参数:path id,query page / size。
输出字段(data.list[] = AclRuleVO):
| 字段 | 类型 | 说明 |
|---|---|---|
rule_id |
int64 | 规则 ID |
name |
string | 规则名 |
describe |
string | 描述 |
matches[] |
array | 匹配条件 |
action |
object | 命中动作(block/page/pass) |
stime / etime |
int64 | 生效起止时间 |
status |
int32 | 1=启用 2=禁用 |
ctime / utime |
int64 | 创建/更新时间 |
可视化建议:表格 + status 徽章 + action.type chip 染色(block 红 / pass 绿 / page 蓝)。
POST /api/guard/policies/{id}/acl/rules — 创建 ACL 规则
鉴权:guard.acl.create
输入参数(AclRuleCreateReq):name / describe / matches[](≥1)/ action / stime / etime。
action.type为block/page时content字段服务端会 base64 编码存储;调用方传明文。
输出字段:返回新建 AclRuleVO。
GET /api/guard/policies/{id}/acl/rules/{rid} — ACL 规则详情
鉴权:guard.acl.view
输入参数:path id + rid。
输出字段:AclRuleVO。
PUT /api/guard/policies/{id}/acl/rules/{rid} — 更新 ACL 规则
鉴权:guard.acl.edit
输入参数:path id + rid,body 同 Create。
输出字段:返回更新后的 AclRuleVO。
DELETE /api/guard/policies/{id}/acl/rules/{rid} — 删除 ACL 规则
鉴权:guard.acl.delete
输入参数:path id + rid。
输出字段:data 为 null。
PUT /api/guard/policies/{id}/acl/rules/{rid}/status — 切换 ACL 规则状态
鉴权:guard.acl.edit
输入参数(AclRuleStatusReq):status int32(1=启用 2=禁用,数字)。
输出字段:data 为 null。
5.6 黑白名单 /api/guard/bwlist
黑白名单分两层:集合(set) 是逻辑容器(黑/白/灰黑/灰白),IP 是集合内的具体条目。灰黑、灰白会在配置生成时分别按黑名单、白名单下发。
GET /api/guard/bwlist/sets — 名单集合列表
鉴权:guard.bwlist.list
输入参数:page / size / keyword。
输出字段(data.list[] = IPSetVO):
| 字段 | 类型 | 说明 |
|---|---|---|
id |
uint64 | 集合 ID |
user_name |
string | 归属用户名(P1.3 替换原 user_id,来源 cloud sys.users) |
name |
string | 集合名 |
policy_id |
string | 关联策略 |
ip_set_type |
int32 | 1=黑名单 2=白名单 3=灰黑名单 4=灰白名单(数字枚举,不是字符串) |
status |
int32 | 1=禁用 2=启用 |
count |
int64 | 总条目数 |
enable_count |
int64 | 启用条目数 |
unable_count |
int64 | 禁用条目数 |
describe |
string | 描述(不是 remark) |
is_default |
bool | 是否默认集合 |
is_private |
bool | 是否私有 |
private_domain_id |
string | 私有集合关联的域名 |
ctime / utime |
int64 | 时间戳 |
可视化建议:
- 推荐图表:表格(主图)+ KPI 卡(黑名单总数 / 白名单总数 / 启用率)
- 派生指标:饼图(
ip_set_type1/2/3/4 占比)
POST /api/guard/bwlist/sets — 创建名单集合
鉴权:guard.bwlist.create
输入参数(BWListSetCreateReq):
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
name |
string | 是 | 集合名 |
ip_set_type |
int32 | 是 | 1=黑名单 2=白名单 3=灰黑名单 4=灰白名单 |
policy_id |
string | 否 | 关联策略 |
status |
int32 | 否 | 1=禁用 2=启用,默认 2 |
describe |
string | 否 | 描述 |
输出字段:返回新建 IPSetVO。
当
policy_id非空时,后端会把集合同步到策略与该策略下域名的黑白名单配置;后续添加、批量添加或删除 IP 会触发配置下发。
PUT /api/guard/bwlist/sets/{id} — 更新名单集合
鉴权:guard.bwlist.edit
输入参数(BWListSetUpdateReq):name / status / describe(全部可选)。
输出字段:返回更新后的 IPSetVO。
修改
status会同步策略/域名配置并触发下发:启用集合进入黑/白名单,禁用集合进入禁用列表。
DELETE /api/guard/bwlist/sets/{id} — 删除名单集合
鉴权:guard.bwlist.delete
输入参数:path id。
输出字段:data 为 null。会级联删除集合内所有 IP 条目。
删除集合会同时从策略/域名黑白名单配置中解绑,并触发相关域名重新下发。
GET /api/guard/bwlist/sets/{id}/ips — 集合内 IP 列表
鉴权:guard.bwlist.ip_list
输入参数:path id = 集合 ID;query page / size。
输出字段(data.list[] = IPVO):
| 字段 | 类型 | 说明 |
|---|---|---|
id |
uint64 | 条目 ID |
ipset_id |
uint64 | 所属集合 |
ip_addr |
string | IP 或 CIDR(不是 ip) |
status |
bool | true=启用 false=禁用,默认 true |
ctime / utime |
int64 | 时间戳 |
不存在
expires_at/remark字段。
可视化建议:表格。
POST /api/guard/bwlist/sets/{id}/ips — 单条添加 IP
鉴权:guard.bwlist.ip_add
输入参数(BWListIPAddReq):
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
ip_addr |
string | 是 | IP 或 CIDR |
status |
bool | 否 | 默认 true |
输出字段:返回新建 IPVO。
POST /api/guard/bwlist/sets/{id}/ips/batch — 批量添加 IP
用途:一次导入数百条 IP(如威胁情报源),减少多次往返开销。
鉴权:guard.bwlist.ip_add
输入参数(BWListIPBatchAddReq):
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
ips[] |
array | 是 | 至少 1 项;每项 {ip_addr, status?} |
输出字段:data 为 null 或返回新增 ID 列表(按实现)。
POST /api/guard/bwlist/sets/{id}/ips/batch/delete — 批量删除 IP
用途:一次删除集合下多条 IP(如清理过期封禁),一个事务原子完成,避免逐条删除的部分失败与审计刷屏。
鉴权:guard.bwlist.ip_delete
输入参数(BWListIPBatchDeleteReq):
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
ip_ids[] |
array<int64> | 是 | 至少 1 项;要删除的 IP 条目 ID。删除范围限定在集合 {id} 内,不属于该集合的 ID 会被忽略 |
输出字段:data.deleted 为实际删除条数。集合内无任一匹配返回 404。
DELETE /api/guard/bwlist/ips/{id} — 删除单条 IP
重要:删除路径是顶级路径
DELETE /api/guard/bwlist/ips/{id},不是嵌套在 sets 下的DELETE /sets/{sid}/ips/{id}。
鉴权:guard.bwlist.ip_delete
输入参数:path id = IP 条目 ID。
输出字段:data 为 null。
5.7 IP 转发 /api/guard/forwards
这是 TCP/UDP 端口转发(4 层),不是路径转发 / 反向代理(7 层)。
GET /api/guard/forwards — IP 转发列表
鉴权:guard.forward.list
输入参数:
| 字段 | 类型 | 说明 |
|---|---|---|
page / size |
int | 标准分页 |
user_id |
string | 按归属用户过滤 |
domain_id |
string | 按域名过滤 |
status |
int32 | 1=禁用 2=启用 |
keyword |
string | 搜索 domain / describe |
输出字段(data.list[] = ForwardVO):
| 字段 | 类型 | 说明 |
|---|---|---|
id |
uint64 | 转发 ID |
user_id |
string | 归属用户 UUID(保留兼容老平台) |
user_name |
string | 归属用户名(P1.3 新增,来源 cloud sys.users) |
domain |
string | 转发的域名/IP |
domain_id |
string | 关联域名 ID |
schema |
int32 | 3=TCP 4=UDP,默认 3 |
port |
int32 | 端口 1-65535 |
node_ipaddrs |
string | 源 IP 列表(逗号分隔) |
describe |
string | 描述 |
status |
int32 | 1=禁用 2=启用 |
src_setting |
json | 源设置 raw JSON |
adv_settings |
json | 高级设置 raw JSON |
node_setting |
json | 节点设置 raw JSON |
dev_setting |
string | 设备设置 |
ctime / utime |
int64 | 时间戳 |
可视化建议:
- 推荐图表:表格 + status / schema 双 chip
- 派生指标:饼图(TCP/UDP 占比)
POST /api/guard/forwards — 创建 IP 转发
鉴权:guard.forward.create
输入参数(ForwardCreateReq):
| 字段 | 类型 | 必填 | 取值 | 说明 |
|---|---|---|---|---|
domain |
string | 是 | *.example.com |
转发域名 |
domain_id |
string | 是 | d_8a3b1c |
关联域名 |
port |
int32 | 是 | 443 |
1-65535 |
schema |
int32 | 否 | 3 |
3=TCP(默认)/4=UDP |
node_ipaddrs |
string | 否 | 10.0.0.1,10.0.0.2 |
源 IP 列表 |
describe |
string | 否 | 描述 | |
status |
int32 | 否 | 2 |
1=禁 2=启用 |
src_setting / adv_settings / node_setting |
json | 否 | raw JSON 配置 | |
dev_setting |
string | 否 | 设备配置 |
不存在
source_path/target字段。
输出字段:返回新建 ForwardVO。
GET /api/guard/forwards/{id} — IP 转发详情
鉴权:guard.forward.view
输入参数:path id。
输出字段:ForwardVO。
PUT /api/guard/forwards/{id} — 更新 IP 转发
鉴权:guard.forward.edit
输入参数:path id,body 同 Create(字段全部可选)。
输出字段:返回更新后的 ForwardVO。
DELETE /api/guard/forwards/{id} — 删除 IP 转发
鉴权:guard.forward.delete
输入参数:path id。
输出字段:data 为 null。
5.8 调度管理 /api/guard/schedules
本模块只做 DNS 解析调度(域名解析模式切换 / 批量启停记录)。 旧版 cron 定时任务接口已下架。
⚠️ 异步生效约定:本组接口不直接调用三方 DNS API,所有写操作仅落库老平台
guard_db.dns_records+guard_db.dns_affairs,最终通过 NSQ topic=dns通知 zdns 服务异步生效。前端 / 调用方必须轮询 affairs 接口获取最终状态(初始AffairsStatus_Start→AffairsStatus_Succeed/AffairsStatus_Faild)。⚠️ 数据真值源:
dns_records.group_type是模式真相源,guard_configs.parsing_state异步同步,均来自老平台guard_db;存在最长 30s 不一致窗口。VO 同时返回两者,前端在不一致时显示"同步中" badge。
5.8.1 域名调度
GET /api/guard/schedules/domains — 域名列表
鉴权:guard.schedule.list
输入参数:
| 字段 | 类型 | 说明 |
|---|---|---|
page / size |
int | 分页(size 上限 100) |
keyword |
string | 按域名模糊搜索 |
user_id |
string | 按归属用户过滤(仅超管/总代有效) |
mode |
int32 | 0=全部 / 1=源站(SRC) / 2=节点(NODE) |
输出字段(data = ScheduleDomainListResp):
| 字段 | 类型 | 说明 |
|---|---|---|
list[].domain_id |
string | 域名 ID(guard_configs.domain_id) |
list[].domain_name |
string | 域名 |
list[].user_id / user_name |
string | 归属用户 |
list[].parsing_state |
int32 | guard_configs.parsing_state(1=SRC / 2=NODE) |
list[].dns_group_type |
int32 | dns_records.group_type 多数票(真值源,1=SRC / 2=NODE) |
list[].src_count |
int | group_type=1 的记录数 |
list[].node_count |
int | group_type=2 的记录数 |
list[].src_records[] |
array | 源站解析摘要:subdomain / record_type / record_line / value / status |
list[].node_records[] |
array | 节点解析摘要:subdomain / record_type / record_line / value / status |
list[].last_affair_status |
string | 最近一条事务状态(AffairsStatus_Start / AffairsStatus_Succeed / AffairsStatus_Faild) |
list[].last_affair_ctime |
int64 | 最近一条事务创建时间(毫秒) |
list[].last_affair_message |
string | 最近一条事务消息(HTML 片段) |
total |
int64 | 总条数 |
POST /api/guard/schedules/domains/{id}/switch-mode — 切换源站/节点
鉴权:guard.schedule.switch
输入参数:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
path id |
string | 是 | domain_id |
body target_mode |
int32 | 是 | 1=源站(SRC) / 2=节点(NODE) |
body comment |
string | 否 | 事务备注(写入 dns_affairs.message) |
实现要点:guard_db 单库事务内 SELECT FOR UPDATE 锁住该域名全部 dns_records → 更新 group_type 与 switch_state=2(切换中)→ INSERT dns_affairs(status=AffairsStatus_Start)→ 提交后 NSQ Cmd=0 通知。
输出字段:返回新建 ScheduleAffairVO,前端应将 affairs_id 写入轮询轮换。
POST /api/guard/schedules/domains/{id}/init — 初始化解析
鉴权:guard.schedule.init
输入参数:path id(domain_id);body 可选 comment。
实现要点:读取 guard_domain_settings 的源站/调度配置与 domain_node_ships 节点绑定,锁住该域名旧 dns_records 后删除并重建源站/节点记录;随后 INSERT dns_affairs,以 NSQ Cmd=0 通知 zdns 同步一次。
输出字段:返回新建 ScheduleAffairVO。
POST /api/guard/schedules/domains/{id}/reset — 重置解析
鉴权:guard.schedule.reset
输入参数:path id(domain_id);body 可选 comment。
实现要点:所有 dns_records.switch_state 归位为 1,status 回滚到 last_status;落事务后 NSQ Cmd=0 通知。
输出字段:返回新建 ScheduleAffairVO。
GET /api/guard/schedules/domains/{id}/records — 域名解析记录
鉴权:guard.schedule.records
输入参数:
| 字段 | 类型 | 说明 |
|---|---|---|
path id |
string | domain_id |
group_type |
int32 | 1=SRC / 2=NODE |
status |
int32 | 1=禁用 / 2=启用 |
page / size |
int | 分页 |
输出字段(data = ScheduleRecordsResp):
| 字段 | 类型 | 说明 |
|---|---|---|
list[] |
DnsRecordVO |
解析记录视图 |
list[].record_id |
string | 主键 |
list[].associated_id |
string | DNS 服务商侧解析记录 ID,用于确认记录已在 ZDNS/服务商侧重建或关联 |
list[].domain / subdomain / value |
string | 域 / 子域 / 解析值 |
list[].record_type |
int32 | DNS 记录类型内部编码 |
list[].record_line |
int32 | 解析线路 |
list[].ttl |
int64 | TTL(秒) |
list[].status / last_status |
int32 | 1=禁用 / 2=启用 |
list[].group_type |
int32 | 1=SRC / 2=NODE |
list[].switch_state |
int32 | 1=就绪 / 2=切换中 |
list[].ctime / utime |
int64 | 时间戳(毫秒) |
直查
zdns_db.dns_records,只读,不落事务。
5.8.2 解析调度
POST /api/guard/schedules/records/batch-status — 批量启停记录
鉴权:guard.schedule.batch
输入参数(ScheduleBatchStatusReq):
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
record_ids |
string[] | 是 | 目标 record_id 集合 |
status |
int32 | 是 | 1=禁用 / 2=启用 |
comment |
string | 否 | 事务备注 |
实现要点:UPDATE dns_records SET last_status=status, status=? WHERE record_id IN (?);落事务后 NSQ Cmd=0 通知。
输出字段:返回新建 ScheduleAffairVO。
5.8.3 事务记录
GET /api/guard/schedules/affairs — 事务列表
鉴权:guard.schedule.affairs
输入参数:
| 字段 | 类型 | 说明 |
|---|---|---|
page / size |
int | 分页 |
user_id |
string | 按归属用户过滤 |
status |
string | AffairsStatus_Start / AffairsStatus_Succeed / AffairsStatus_Faild |
ctime_from / ctime_to |
int64 | 时间范围(毫秒) |
domain_id |
string | 按受影响 domain 过滤(实现走 content LIKE) |
输出字段(data = ScheduleAffairListResp):见下方 ScheduleAffairVO。
GET /api/guard/schedules/affairs/{id} — 事务详情
鉴权:guard.schedule.affairs
输入参数:path id(affairs_id)。
输出字段(data = ScheduleAffairVO):
| 字段 | 类型 | 说明 |
|---|---|---|
affairs_id |
string | 事务 ID,格式 {ts}_{rand10} |
user_id / user_name |
string | 操作人 |
status |
string | AffairsStatus_Start / AffairsStatus_Succeed / AffairsStatus_Faild(字符串枚举,对齐老平台 MarshalJSON 行为) |
message |
string | 事务消息,含 HTML 片段(如 <br>) |
content |
string | 受影响 domain_id,逗号分隔 |
json_content |
object | 扩展 JSON,含 outbox 重试计数等 |
affairs_oper |
string | AffairsOperType_Page / AffairsOperType_Cron / AffairsOperType_Cli |
ctime / utime |
int64 | 创建/更新时间(毫秒) |
轮询建议:前端发起写操作后,每 2~5s 轮询一次本接口,直到
status切换为Succeed或Faild;若长时间停在Start,说明 outbox 重试中,可在 UI 显示"同步中"。
5.9 WAF 规则 /api/guard/waf/rules
WAF 规则组挂在策略(
policy_id)下,一个规则组含若干子规则(rules[]),由网关侧匹配zone/pattern决定命中后action(拦截 / 记录 / 验证码)。⚠️ 状态约定:本组接口的
status字段统一约定1=禁用2=启用(S-6 修复后已与forwards/bwlist/schedules对齐)。POST /status接口的oneof校验也是1|2。⚠️ 路径 ID 取
tag:PUT/DELETE /api/guard/waf/rules/{id}中{id}是规则组的tag(uint64 主键),不是rule_id(业务编号)。前端从列表的tag字段取值。
GET /api/guard/waf/rules — WAF 规则组列表
鉴权:guard.waf.list
输入参数:
| 字段 | 类型 | 说明 |
|---|---|---|
page / size |
int | 标准分页 |
policy_id |
string | 按策略过滤(不传则返回当前用户可见的全部规则组) |
输出字段(data.list[] = WafGroupVO):
| 字段 | 类型 | 说明 |
|---|---|---|
tag |
uint64 | 规则组主键(路径 {id} 用) |
rule_id |
int64 | 业务规则编号 |
name |
string | 规则组名称 |
describe |
string | 描述 |
waf_type |
int32 | WAF 类型内部编码 |
sub_rule_condition |
int32 | 子规则组合逻辑(0=AND / 1=OR,按 model 实现为准) |
scope |
string | 作用域(domain / path / 留空 = 全部) |
action |
int32 | 1=block(拦截) 2=log(记录) 3=captcha(验证码) |
status |
int32 | 1=禁用 2=启用 |
policy_id |
string | 所属策略 ID |
rules[] |
WafRuleVO |
子规则列表(每条含 zone / pattern / pattern_type / is_not) |
ctime / utime |
int64 | 时间戳(毫秒) |
WafRuleVO(子规则)字段:
| 字段 | 类型 | 说明 |
|---|---|---|
tag |
uint64 | 子规则主键 |
rule_id |
int64 | 业务规则编号 |
group_id |
int64 | 所属规则组(关联 WafGroupVO.tag / rule_id) |
zone |
string | 匹配区域(如 URL / ARGS / HEADER / BODY) |
sub_field |
string | 区域内的子字段(如 header name) |
pattern_type |
int32 | 匹配类型(精确 / 正则 / 包含等内部编码) |
pattern |
string | 匹配表达式 |
describe |
string | 描述 |
is_not |
bool | true = 取反匹配 |
ctime / utime |
int64 | 时间戳(毫秒) |
可视化建议:
- 推荐图表:表格 +
action/status双 chip +rules.length数字徽章 - 派生指标:按
action聚合的饼图(block / log / captcha 占比)
POST /api/guard/waf/rules — 创建 WAF 规则组
鉴权:guard.waf.create
输入参数(WafGroupCreateReq):
| 字段 | 类型 | 必填 | 取值 | 说明 |
|---|---|---|---|---|
name |
string | 是 | "SQL 注入防护" |
规则组名称 |
policy_id |
string | 是 | "1" |
挂载策略 |
rule_id |
int64 | 否 | 业务编号,不传由后端生成 | |
describe |
string | 否 | 描述 | |
waf_type |
int32 | 否 | WAF 类型内部编码 | |
sub_rule_condition |
int32 | 否 | 子规则组合逻辑 | |
scope |
string | 否 | "*.example.com" |
作用域 |
action |
int32 | 否 | 1 |
1=block / 2=log / 3=captcha |
status |
int32 | 否 | 2 |
1=禁用 2=启用 |
rules[] |
object[] | 否 | 子规则列表(字段同 WafRuleReq,见下) |
WafRuleReq(子规则请求体):
| 字段 | 类型 | 说明 |
|---|---|---|
rule_id |
int64 | 业务编号,不传由后端生成 |
zone |
string | 匹配区域 |
sub_field |
string | 区域内的子字段 |
pattern_type |
int32 | 匹配类型 |
pattern |
string | 匹配表达式 |
describe |
string | 描述 |
is_not |
bool | true = 取反 |
示例:
curl -X POST https://waf.example.com/api/guard/waf/rules \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "SQL 注入防护",
"policy_id": "1",
"describe": "OWASP Top 10 SQLi 黑名单",
"action": 1,
"status": 2,
"rules": [
{ "zone": "ARGS", "pattern_type": 2, "pattern": "union\\s+select", "describe": "SQLi: union select" }
]
}'
输出字段:返回新建 WafGroupVO(含 tag、rules[] 已落库的子规则)。
不存在字段:
enabled布尔(用status整数)/description(用describe)/domains[](作用域用scope字符串)。
PUT /api/guard/waf/rules/{id} — 更新 WAF 规则组
鉴权:guard.waf.edit
输入参数(path id = 规则组 tag;body WafGroupUpdateReq,字段全部可选,按 flag 增量更新;rules[] 全量替换):
| 字段 | 类型 | 说明 |
|---|---|---|
name |
string | 规则组名称 |
describe |
string | 描述 |
waf_type |
*int32 | 指针类型,未传不动 |
sub_rule_condition |
*int32 | 指针类型 |
scope |
string | 作用域 |
action |
*int32 | 指针类型 |
rules[] |
object[] | 全量替换子规则列表 |
本接口不更新
status——启停切换走独立的PUT /api/guard/waf/rules/{id}/status。
输出字段:返回更新后的 WafGroupVO。
DELETE /api/guard/waf/rules/{id} — 删除 WAF 规则组
鉴权:guard.waf.delete
输入参数:path id(规则组 tag)。
实现要点:级联删除子规则(waf_rules.group_id = tag)。
输出字段:data 为 null。
PUT /api/guard/waf/rules/{id}/status — 切换 WAF 规则组启停
鉴权:guard.waf.status
输入参数(path id = 规则组 tag;body WafStatusReq):
| 字段 | 类型 | 必填 | 取值 | 说明 |
|---|---|---|---|---|
status |
int32 | 是 | 1 / 2 |
1=禁用 2=启用,oneof=1 2 校验 |
示例:
curl -X PUT https://waf.example.com/api/guard/waf/rules/42/status \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{ "status": 1 }'
输出字段:data 为 null。
§6 Analytics 统计分析
📊 Analytics 统计分析 · 18 paths(含 80+ chart-key 单图接口)· 用于构建 WAF 监控大屏、运营报表、处置闭环
所有/api/analytics/*路径已对外,只能增加字段或新增接口,不能修改或删除已发布路径。
完整 chart-key → 数据形态映射见各小节"chart-key 索引表",每行都明确推荐图表。
6.0 本章统一调用约定
Analytics 接口数量多但大多是同构的图表查询。本章用"统一约定 + 索引表 + 特殊接口展开"组织。
鉴权与权限
Header:Authorization: Bearer <token> 或 Authorization: ApiKey zck_...,可附加 Accept-Language: zh-CN / en-US。
权限分三类:
| 类型 | 判断方式 | 示例 |
|---|---|---|
| 页面级只读 | analytics.<page>.view |
GET /api/analytics/overview/kpi 需要 analytics.overview.view |
| 特殊动作 | 表格或小节单独标出 | POST /api/analytics/overview/export 需要 analytics.overview.export |
| 登录态 | 只要求认证,不要求具体业务权限 | GET /api/analytics/glossary |
使用 API Key 时,Key 的 scopes 必须覆盖接口所需权限。例如调用 GET /api/analytics/access/status,Key 至少包含 analytics.access.view。
单图 GET 调用模板
curl -sS 'https://waf.example.com/api/analytics/access/status?window=last_24h&site_id=site-001' \
-H "Authorization: ApiKey $ZCLOUD_API_KEY" \
-H 'Accept-Language: zh-CN'
返回统一 JSON 信封,图表 data 固定使用 Chart 统一契约(docs/specs/chart-contract.md)。这是新系统对外唯一契约;老数据库表、聚合表和 ES 索引只作为内部数据源,不影响调用方入参或响应结构。
图表 data 固定 5 字段,禁止 series / totals / kpis / points / list 作为对外顶层字段:
| 字段 | 类型 | 说明 |
|---|---|---|
chart_key |
string | 与请求 <chart> 完全一致 |
render_hint |
enum | 8 词汇之一:kpi / categorical_distribution / categorical_distribution_over_time / time_series_single / time_series_multi / topn / geo / table,前端据此选渲染器 |
schema |
object | 列元信息 {dimensions:[{name,type,unit?,values?}], measures:[{name,type,unit?,format?}]} |
rows |
array | tidy 长表,一行一个观测(禁止横铺),空数据返回 [] |
meta |
object | 调试字段 {source, cache, latency_ms, partial?, available?, ...} |
window.granularity 不是入参:客户传
window=last_24h,后端按时间窗大小自动选择 5m/1h/1d 聚合表,并在响应里回填实际命中的granularity。
Batch 调用模板
适用于 POST /api/analytics/batch 与 POST /api/analytics/<page>/batch。
curl -sS -X POST https://waf.example.com/api/analytics/overview/batch \
-H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"time_window": "last_24h",
"site_id": "",
"domain_id": "",
"compare": false,
"charts": [
{ "key": "kpi" },
{ "key": "bandwidth" }
]
}'
Batch 响应的 data.data 以 chart-key 为键;data.meta 给出整体耗时、缓存命中率、失败图表数和实际时间窗。单个 chart 失败时优先查看该 chart 节点里的 partial / error 字段。
6.1 术语表
GET /api/analytics/glossary — 统计术语表
用途:返回统计分析术语表,前端 tooltip 用此渲染"什么是 QPS / 拦截率"等说明。
鉴权:登录态
输入参数:无。
输出字段:
| 字段 | 类型 | 说明 |
|---|---|---|
data.terms |
map<string,string> | key=术语短名,value=多语言解释 |
可视化建议:
- 推荐图表:不直接做图;前端图表组件挂上 tooltip 时按 chart-key 在 terms map 里查询解释
示例响应:
{
"code": 0,
"data": {
"terms": {
"qps": "每秒请求数",
"block_rate": "拦截率"
}
}
}
6.2 跨页 Batch
POST /api/analytics/batch — 跨页通用批量查询
用途:在前端大屏页面初始化时一次性请求多个 chart-key,省去 N 次单图 GET 往返。后端并行执行各子查询并合并响应。
鉴权:按 page 字段映射到对应 analytics.<page>.view
输入参数(请求体):
| 字段 | 类型 | 必填 | 取值/示例 | 说明 |
|---|---|---|---|---|
page |
string | 是 | overview |
必须是当前已支持页面之一:overview / access / protect / ai / bot / alert / health / ops / closure / cache |
time_window |
string | 否 | last_24h |
同 window |
stime / etime |
int64 | 否 | 1746748800000 |
自定义时间戳 |
site_id |
string | 否 | 站点过滤 | |
domain_id |
string | 否 | 域名过滤 | |
target_user_id |
string | 否 | 客户级切换被查看用户 | |
compare |
bool | 否 | false |
是否启用上一周期对比 |
charts[] |
array | 是 | [{key:"kpi"}] |
至少 1 项 chart-key |
logs(Phase 1 原始日志)和reports(Phase 4 报表中心)是独立 group,不走 batch 模式。
输出字段:
| 字段 | 类型 | 说明 |
|---|---|---|
data.data |
map | key=chart-key;value 固定为 {chart_key, render_hint, schema, rows, meta} 5 字段 Chart 统一契约 |
data.meta.elapsed_ms |
int | 整体耗时 |
data.meta.cache_hit_ratio |
float | 缓存命中率(0-1) |
data.meta.total_charts |
int | 请求 chart 总数 |
data.meta.failed_charts |
int | 失败 chart 数 |
data.meta.window |
object | 实际命中时间窗 |
可视化建议:
- 推荐图表:本接口本身不直接做图,是数据装载层;前端拿到响应后按 chart-key 分发到各图表组件
- 派生指标:
data.meta.cache_hit_ratio可在 dev 环境做 KPI 数字卡监控大屏的缓存效率
示例请求/响应:
// 请求
{
"page": "overview",
"time_window": "last_24h",
"compare": false,
"charts": [
{ "key": "kpi" },
{ "key": "bandwidth" }
]
}
// 响应
{
"code": 0,
"data": {
"data": {
"kpi": {
"chart_key": "overview/kpi",
"render_hint": "kpi",
"schema": {
"dimensions": [],
"measures": [
{ "name": "domain_count", "type": "integer", "unit": "" },
{ "name": "requests", "type": "integer", "unit": "requests" },
{ "name": "blocked", "type": "integer", "unit": "events" },
{ "name": "block_rate", "type": "percent", "unit": "%" },
{ "name": "qps", "type": "float", "unit": "qps" },
{ "name": "ai_detect", "type": "integer", "unit": "events" }
]
},
"rows": [
{ "domain_count": 8, "requests": 12345, "blocked": 678, "block_rate": 5.49, "qps": 0.143, "ai_detect": 0 }
],
"meta": { "source": "postgres", "cache": "miss", "latency_ms": 10 }
},
"event-type": {
"chart_key": "overview/event-type",
"render_hint": "categorical_distribution",
"schema": {
"dimensions": [{ "name": "event_type", "type": "string" }],
"measures": [{ "name": "count", "type": "integer", "unit": "events" }]
},
"rows": [
{ "event_type": "sql_injection", "count": 1234 },
{ "event_type": "xss", "count": 567 }
],
"meta": { "source": "elasticsearch", "cache": "miss", "latency_ms": 15, "partial": false }
}
},
"meta": {
"elapsed_ms": 22,
"cache_hit_ratio": 0,
"total_charts": 2,
"failed_charts": 0,
"window": { "stime": 1746662400000, "etime": 1746748800000, "granularity": "1h" }
}
}
}
注意:上例中
kpi的 measure 名requests/blocked是对外契约真值名(与pkg/chart/contract真值结构体对齐)。底层数据库字段名不对外暴露,前端严格按schema.measures[].name取值。
POST /api/analytics/{page}/batch — 页面级 Batch
用途:与 POST /api/analytics/batch 等价,但 page 由 URL 决定(前端固定页面调用更直观)。
鉴权:根据 {page} 映射到对应 analytics.<page>.view。
支持的 page 值:
| URL | 权限 |
|---|---|
POST /api/analytics/overview/batch |
analytics.overview.view |
POST /api/analytics/access/batch |
analytics.access.view |
POST /api/analytics/protect/batch |
analytics.protect.view |
POST /api/analytics/ai/batch |
analytics.ai.view |
POST /api/analytics/bot/batch |
analytics.bot.view |
POST /api/analytics/alert/batch |
analytics.alert.view |
POST /api/analytics/health/batch |
analytics.health.view |
POST /api/analytics/ops/batch |
analytics.ops.view |
POST /api/analytics/closure/batch |
analytics.closure.view |
POST /api/analytics/cache/batch |
analytics.cache.view |
输入/输出:与 POST /api/analytics/batch 完全一致;调用方不需要在请求体里再传 page,即使传了也以路径中的页面名为准。
可视化建议:同上。
6.3 单图 GET 调用入口
GET /api/analytics/{page}/{chart} — 单图通用入口
用途:拉取单个 chart-key 的数据。{page} 取值同 batch;{chart} 取值参见各页面小节的 chart-key 索引表。
鉴权:根据 {page} 映射到 analytics.<page>.view(少数特殊 chart 用独立权限,详见各小节)。
输入参数:见 §A 通用查询参数。
输出字段:统一信封 + data:
data固定为 Chart 统一契约:{chart_key, render_hint, schema, rows, meta}schema声明rows的维度列与指标列;调用方不要从底层数据库字段名推断响应结构
可视化建议:前端按 render_hint 自动分发到对应图表组件;复杂图表的列定义以 schema 为准。
6.4 总览页面(Overview)
适用场景:WAF 防护监控大屏首页 KPI + 趋势 + 排行 + 地图。
下表所有 GET 接口都用 §6.0 单图 GET 调用模板、§A 通用查询参数 和 Chart 统一契约响应结构。
| API | chart-key | render_hint | 推荐图表 | 说明 |
|---|---|---|---|---|
GET /api/analytics/overview/kpi |
kpi |
kpi |
KpiGroupCard(6 measure) | 站点数 / requests / blocked / block_rate / qps / ai_detect |
GET /api/analytics/overview/bandwidth |
bandwidth |
time_series_multi |
折线图(双 Y 轴) | 总带宽与回源带宽时序 |
GET /api/analytics/overview/request-attack |
request-attack |
time_series_multi |
折线图(双系列) | 请求量 vs 攻击量对比 |
GET /api/analytics/overview/event-type |
event-type |
categorical_distribution |
饼图 / 环形图 | 事件类型分布(dim=event_type, measure=count) |
GET /api/analytics/overview/waf-type |
waf-type |
categorical_distribution |
饼图 / 环形图 | WAF 命中类型分布 |
GET /api/analytics/overview/geo |
geo |
geo |
中国/世界地图热力 | 攻击来源地理分布 |
GET /api/analytics/overview/top-domains |
top-domains |
topn |
横向 bar / 表格 | 被攻击域名 TOP 5 |
GET /api/analytics/overview/recent-events |
recent-events |
table |
时间线 / 表格(50 条) | 最近 WAF 事件流 |
chart-key 数据形态详解
kpi(render_hint = kpi)
schema.measures 共 6 项:
| measure name | type | unit | 说明 |
|---|---|---|---|
domain_count |
integer | (空) | 站点数 |
requests |
integer | requests | 时间窗内总请求量 |
blocked |
integer | events | 时间窗内总拦截量 |
block_rate |
percent | % | 拦截率 = blocked / requests |
qps |
float | qps | QPS = requests / 窗口秒数 |
ai_detect |
integer | events | AI 识别数(当前固定 0,后续接 ES 实数) |
rows 单行:[ { domain_count, requests, blocked, block_rate, qps, ai_detect } ]。
对外字段名:
requests/blocked是 API 契约字段名。底层数据库若仍使用request_today/attack_today等历史字段,由后端在服务层转换,不暴露给调用方。
推荐图表:KpiGroupCard(6 个 KPI 数字卡),block_rate 用百分比 + 进度条;qps 配迷你 sparkline。
bandwidth / request-attack — 时序双系列
输出 [{ctime: int64ms, bandwidth: float, origin_bandwidth: float}, ...] 或 [{ctime, requests, attacks}, ...]。
推荐图表:折线图,X 轴 ctime,Y 轴双系列。
event-type(render_hint = categorical_distribution)
| schema 部分 | 内容 |
|---|---|
dimensions |
[{ name: "event_type", type: "string" }] |
measures |
[{ name: "count", type: "integer", unit: "events" }] |
rows 长表:[ { event_type: "sql_injection", count: 1234 }, { event_type: "xss", count: 567 }, ... ]。
推荐图表:PieCard(≤8 类自动饼图)/ BarCard(>8 类自动横向 bar);前端按 categorical_distribution 词汇分发。
waf-type — 维度分布
输出 [{key: string, count: int}, ...]。
推荐图表:饼图(≤ 8 类)或环形图。
geo — 地理热力
输出 [{region: string, count: int}, ...],region 为国家/省份名。
推荐图表:地图热力(中国地图 + 世界地图叠加)。
top-domains — 域名排行
输出 [{host: string, attack_count: int}, ...],按 attack_count DESC,最多 5 条。
推荐图表:横向 bar 图。
recent-events — 最近事件流
输出 [{ctime, domain, attack_type, severity, ...}, ...],最多 50 条。
推荐图表:时间线 / 表格(按 ctime 倒序),可点击进入详情。
POST /api/analytics/overview/export — 总览页导出
用途:把 KPI 与图表快照导出为 CSV 或 JSON 文件,供线下分析或汇报。返回原文文件流,不走信封。
鉴权:analytics.overview.export
输入参数(请求体):
| 字段 | 类型 | 必填 | 取值/示例 | 说明 |
|---|---|---|---|---|
format |
string | 是 | csv / json |
导出格式 |
window |
string | 否 | last_24h |
时间窗 |
charts[] |
array | 是 | [{key:"kpi"}] |
要导出的 chart-key 列表 |
输出:直接返回文件流,Content-Type: text/csv 或 application/json,Content-Disposition: attachment。
可视化建议:不适合图表;触发后浏览器下载。
6.5 访问分析页面(Access)
适用场景:流量与质量分析大屏 — 看请求量、流量、缓存命中、状态码、耗时分布、运营商、TOP IP/URL、地域。
| API | chart-key | render_hint | 推荐图表 | 说明 |
|---|---|---|---|---|
GET /api/analytics/access/request-hm |
request-hm |
time_series_single(无 compare)/ time_series_multi(compare) |
LineCard | 请求量趋势;compare=true 走子形态 B(period 维度区分 current/previous) |
GET /api/analytics/access/flow-hm |
flow-hm |
time_series_multi |
LineCard 多线 | 5 measure:total_bytes / request_bytes / response_bytes / upstream_send / upstream_receive |
GET /api/analytics/access/cache-hm |
cache-hm |
time_series_multi |
折线图(双 Y 轴) | 缓存命中次数 + 缓存字节趋势 |
GET /api/analytics/access/bandwidth |
bandwidth |
time_series_multi |
LineCard 多线 | 4 measure:bandwidth / origin_bandwidth / up_bandwidth / down_bandwidth |
GET /api/analytics/access/status |
status |
categorical_distribution_over_time |
StackedBarCard | 4 类 HTTP 状态码(dim=status_class enum["2xx","3xx","4xx","5xx"] + time)按时间堆叠 |
GET /api/analytics/access/flow-duration |
flow-duration |
time_series_multi |
折线图(3 分位) | 请求耗时 P50/P95/P99(D4:仅时间窗 ≤ 24h 走实时计算) |
GET /api/analytics/access/isp |
isp |
categorical_distribution |
饼图 | 运营商分布(移动/联通/电信/其它) |
GET /api/analytics/access/top-ip |
top-ip |
topn |
表格 / 横向 bar(含地理) | 访问 IP TOP(默认 10,可调 top) |
GET /api/analytics/access/top-url |
top-url |
topn |
表格 / 横向 bar | URL TOP,可按 order=bytes_desc/cache_desc 切换排序 |
GET /api/analytics/access/geo |
geo |
geo |
中国/世界地图热力 | 访问来源地理分布 |
chart-key 数据形态详解
request-hm
无 compare(render_hint = time_series_single):
| schema 部分 | 内容 |
|---|---|
dimensions |
[{ name: "time", type: "timestamp", unit: "ms" }] |
measures |
[{ name: "requests", type: "integer", unit: "requests" }] |
rows:[ { time: 1746748800000, requests: 1234 }, ... ]。
开 compare(render_hint = time_series_multi 子形态 B:1 categorical + 1 ts + 1 measure):
| schema 部分 | 内容 |
|---|---|
dimensions |
[{ name: "period", type: "enum", values: ["current","previous"] }, { name: "time", type: "timestamp", unit: "ms" }] |
measures |
[{ name: "requests", type: "integer", unit: "requests" }] |
rows:[ { period: "current", time: ..., requests: ... }, { period: "previous", time: ..., requests: ... }, ... ] 长表,按 period pivot 成 2 条 series。
推荐图表:LineCard;compare 模式按 period pivot 双色实虚线,前端自动处理。
flow-hm(render_hint = time_series_multi)
| schema 部分 | 内容 |
|---|---|
dimensions |
[{ name: "time", type: "timestamp", unit: "ms" }] |
measures |
5 项:total_bytes / request_bytes / response_bytes / upstream_send / upstream_receive(type=integer,unit=bytes,format=iec) |
rows:[ { time: ..., total_bytes: ..., request_bytes: ..., response_bytes: ..., upstream_send: ..., upstream_receive: ... }, ... ]。
推荐图表:LineCard 多线(5 条)/ 堆叠面积。
cache-hm — 缓存趋势
输出 [{ctime, cache_count, cache_bytes, cache_response}, ...]。
真值字段(D8):底层用
total_cache_count/total_cache_bytes/total_cache_response_bytes;返回时映射为cache_count/cache_bytes/cache_response。
推荐图表:双 Y 轴折线(左轴次数,右轴字节)。
bandwidth(render_hint = time_series_multi)
| schema 部分 | 内容 |
|---|---|
dimensions |
[{ name: "time", type: "timestamp", unit: "ms" }] |
measures |
4 项:bandwidth / origin_bandwidth / up_bandwidth / down_bandwidth(type=float,unit=bps) |
rows:[ { time: ..., bandwidth: ..., origin_bandwidth: ..., up_bandwidth: ..., down_bandwidth: ... }, ... ]。
推荐图表:LineCard 多线(4 条)。
status(render_hint = categorical_distribution_over_time)
| schema 部分 | 内容 |
|---|---|
dimensions |
[{ name: "status_class", type: "enum", values: ["2xx","3xx","4xx","5xx"] }, { name: "time", type: "timestamp", unit: "ms" }] |
measures |
[{ name: "count", type: "integer", unit: "requests" }] |
rows tidy 长表(禁止横铺 c2xx/c3xx/c4xx/c5xx):
[
{ "status_class": "2xx", "time": 1746748800000, "count": 1200 },
{ "status_class": "3xx", "time": 1746748800000, "count": 30 },
{ "status_class": "4xx", "time": 1746748800000, "count": 8 },
{ "status_class": "5xx", "time": 1746748800000, "count": 0 },
{ "status_class": "2xx", "time": 1746752400000, "count": 1340 },
...
]
每个时间点必须覆盖 4 个 status_class(缺则补 count: 0,前端堆叠柱图依赖完整网格)。
推荐图表:StackedBarCard(按 status_class 堆叠时序)。前端按 categorical_distribution_over_time 词汇分发。
flow-duration — 耗时分位
输出 {p50, p95, p99} 或时序数组。
真值边界(D4):百分位字段仅时间窗 ≤ 24h 时由 ES 实时计算;窗口更长时该接口返回
available:false。
推荐图表:折线图(3 分位曲线)或 KPI 数字卡(3 个)。
isp — 运营商分布
输出 {mobile, unicom, telecom, other}。
推荐图表:饼图(4 段)。
top-ip — IP TOP
输出 [{remote_addr, count, country, region, isp}, ...],最多 top 条。
推荐图表:表格(含国旗 + 地区 + 运营商);或横向 bar 图。
top-url — URL TOP
输出 [{url, request_count, request_bytes, cache_bytes}, ...]。
推荐图表:表格(默认);或横向 bar(可按字节/缓存切换)。
geo — 地理热力
输出 [{region, count}, ...]。
推荐图表:地图热力。
6.6 防护分析页面(Protect)
适用场景:WAF / CC / DDoS 三大防护引擎的命中分析。
| API | chart-key | render_hint | 推荐图表 | 说明 |
|---|---|---|---|---|
GET /api/analytics/protect/overview |
overview |
kpi |
多 KPI 卡 | WAF/CC/DDoS 总量汇总(时序由 statistics 系列独立 chart 提供) |
GET /api/analytics/protect/waf/statistics |
waf/statistics |
time_series_multi |
折线图 | WAF 命中趋势(waf 命中数 + 总攻击数) |
GET /api/analytics/protect/waf/types |
waf/types |
categorical_distribution |
饼图 / 横向 bar | WAF 命中类型分布(SQL 注入/XSS/扫描器等) |
GET /api/analytics/protect/waf/top-ip |
waf/top-ip |
topn |
RankingCard / 横向 bar | dim=ip(string), measure=count(events),country/province 进 meta.row_extras |
GET /api/analytics/protect/waf/geo |
waf/geo |
geo |
GeoHeatmapCard | dim=country(geo), measure=count(events);provinces 暂存 meta.provinces |
GET /api/analytics/protect/cc/statistics |
cc/statistics |
time_series_single |
折线图 | CC 命中趋势 |
GET /api/analytics/protect/cc/top-ip |
cc/top-ip |
topn |
表格 / 横向 bar | CC 攻击 IP TOP |
GET /api/analytics/protect/cc/geo |
cc/geo |
geo |
地图热力 | CC 攻击地域 |
GET /api/analytics/protect/cc/top-url |
cc/top-url |
topn |
表格 | CC 攻击 URL TOP |
GET /api/analytics/protect/ddos/statistics |
ddos/statistics |
time_series_multi |
折线图(双 Y 轴) | DDoS 事件数 + 峰值带宽时序 |
GET /api/analytics/protect/ddos/types |
ddos/types |
categorical_distribution |
饼图 / 横向 bar | DDoS 攻击类型分布(syn flood/udp flood 等) |
GET /api/analytics/protect/ddos/top-ip |
ddos/top-ip |
topn |
表格 | DDoS 源 IP TOP(含峰值带宽) |
chart-key 数据形态详解(关键差异)
overview:render_hint = kpi,rows = [{waf, cc, ddos_bytes}](单行汇总,dimensions=[],measures=waf/cc/ddos_bytes)。推荐 3 KPI 卡;时序由 protect/waf/statistics 与 protect/ddos/statistics 独立 chart 提供。
waf/statistics:render_hint = time_series_multi,rows = [{time, waf, attack_count}, ...] tidy 长表(time=ms 时间戳,2 measure 双线)。推荐折线图(双系列)。
waf/types / ddos/types:render_hint = categorical_distribution,rows = [{waf_type, count}, ...] / [{ddos_type, count}, ...] tidy 长表,用饼图或横向 bar。
waf/top-ip(render_hint = topn)
| schema 部分 | 内容 |
|---|---|
dimensions |
[{ name: "ip", type: "string" }] |
measures |
[{ name: "count", type: "integer", unit: "events" }] |
rows:[ { ip: "1.2.3.4", count: 1234 }, { ip: "5.6.7.8", count: 567 }, ... ],已按 count DESC 排序。country / province 等附加列进 meta.row_extras(前端按需取,不入 schema 列)。
推荐图表:RankingCard / 横向 bar 图。
ddos/top-ip:含地理的 IP TOP,推荐含国旗的表格。
waf/geo(render_hint = geo)
| schema 部分 | 内容 |
|---|---|
dimensions |
[{ name: "country", type: "geo" }] |
measures |
[{ name: "count", type: "integer", unit: "events" }] |
rows:[ { country: "China", count: 1234 }, { country: "US", count: 567 }, ... ]。
provinces 数据暂存
meta.provinces(结构[{province, count}])。当前前端 GeoHeatmapCard 渲染主图用rows,省级钻取用meta.provinces;后续如需要省级独立图表,再新增protect/waf/geo-provinceschart-key。
推荐图表:GeoHeatmapCard(中国 / 世界地图热力)。
cc/geo:render_hint = geo,rows = [{country, count}, ...],地图热力。
ddos/statistics:render_hint = time_series_multi,rows = [{time, events, bandwidth}, ...] tidy 长表(events=integer events,bandwidth=float bytes/iec)。推荐双 Y 轴折线。
6.7 AI 识别页面(AI)
当前 AI 页面路径已发布。
/logs走独立analytics.ai.logs权限,其它走analytics.ai.view。
第一版多数 chart 返回 BatchChartResult 占位(rows: [],meta.available = false,meta.reason说明原因),路径与契约稳定,后端可在保持路径不变的前提下逐步升级真实数据。
| API | chart-key | 推荐图表 | 说明 |
|---|---|---|---|
GET /api/analytics/ai/attack-trend |
attack-trend |
折线图 | AI 攻击趋势 |
GET /api/analytics/ai/top-ip |
top-ip |
表格 / 横向 bar | AI 命中 IP TOP |
GET /api/analytics/ai/top-url |
top-url |
表格 | AI 命中 URL TOP |
GET /api/analytics/ai/detection |
detection |
KPI 数字卡 / 雷达图 | AI 检测能力面板 |
GET /api/analytics/ai/test-results |
test-results |
表格 / 柱图 | AI 测试结果 |
GET /api/analytics/ai/logs |
logs |
表格(明细,分页) | AI 命中日志明细(独立权限 analytics.ai.logs) |
占位响应:未升级的 chart 返回标准 BatchChartResult(5 字段齐全,
rows: [],meta.available = false,meta.reason说明原因),前端应渲染"暂无数据"占位卡片,不展示假数据。
6.8 主动防护 / Bot 页面
适用场景:识别和分析爬虫/Bot 流量。
| API | chart-key | 推荐图表 | 说明 |
|---|---|---|---|
GET /api/analytics/bot/statistics |
statistics |
KPI(6 个) | Bot 请求/会话/IP/已知未知 Bot 总览(趋势线由独立 chart 提供,未拆时不展示) |
GET /api/analytics/bot/advance-warn |
advance-warn |
表格 | Bot 预警列表 |
GET /api/analytics/bot/browser |
browser |
饼图 | 浏览器分布(chrome/safari/firefox/edge/wechat/other) |
GET /api/analytics/bot/operating |
operating |
饼图 | 操作系统分布(android/ios/windows/mac/other) |
GET /api/analytics/bot/geo |
geo |
地图热力 | Bot 地域分布 |
GET /api/analytics/bot/top-agent |
top-agent |
表格 / 横向 bar | User-Agent TOP |
GET /api/analytics/bot/top-ip |
top-ip |
表格(含地理) | Bot IP TOP |
GET /api/analytics/bot/scatter |
scatter |
散点图 | Bot 预警散点(X=ctime / Y=top_visit_count,size=top_ip_count) |
GET /api/analytics/bot/sessions |
sessions |
表格(分页) | Bot 会话列表(独立权限 analytics.bot.session) |
GET /api/analytics/bot/sessions/{sid} |
- | 时间线 | 单个 Bot 会话时间线详情(独立权限 analytics.bot.session) |
chart-key 数据形态详解
statistics:render_hint = kpi,rows = [{requests, sessions, ips, known_bot, unknown_bot, req_per_session}](单行汇总,6 measure)。推荐 6 个 KPI 卡;请求/会话趋势由独立 chart 提供(当前未拆,需要时新增 bot/sessions-trend)。
browser:render_hint = categorical_distribution,rows = [{browser, count}, ...](6 行 enum:chrome/safari/firefox/edge/wechat/other),饼图。
operating:render_hint = categorical_distribution,rows = [{os, count}, ...](5 行 enum:android/ios/windows/mac/other),饼图。
scatter:render_hint = table(无 scatter hint,table 兜底),rows = [{time, session_id, top_visit_count, top_ip_count, top_ua_count}, ...],由前端解析 X/Y/size 渲染散点图。
sessions/{sid}:render_hint = table,rows = [{time, uri, remote_addr, method, status}, ...](5 字段裁剪),是该 session 的全量访问记录时间线;未传 session_id(通过 query order 参数)时返空。
6.9 告警统计页面(Alert)
适用场景:告警总览 + 列表 + 单条详情 + 确认。
| API | 方法 | chart-key | 推荐图表 | 说明 |
|---|---|---|---|---|
GET /api/analytics/alert/total |
GET | total |
KPI 数字卡 | 告警总数 |
GET /api/analytics/alert/hm |
GET | hm |
折线图 / 热力图 | 告警趋势(按 ctime 聚合 count) |
GET /api/analytics/alert/types |
GET | types |
饼图 | 告警类型分布(按 policy_type) |
GET /api/analytics/alert/domains |
GET | domains |
横向 bar / 表格 | 告警域名排行 |
GET /api/analytics/alert/list |
GET | list |
表格(分页) | 告警列表 |
GET /api/analytics/alert/{id} |
GET | - | 详情卡片 | 单条告警详情(含处置元信息) |
PATCH /api/analytics/alert/{id}/ack |
PATCH | - | 不适合图表 | 确认指定告警 |
GET /api/analytics/alert/{id} 输出字段
| 字段 | 类型 | 说明 |
|---|---|---|
id |
int | 告警 ID |
uuid |
string | 告警 UUID |
policy_type |
string | 告警类型 |
title / body |
string | 告警标题 / 内容 |
domain / domain_id |
string | 关联域名 |
status |
int | 告警状态(0/1/2/3,参见 D10) |
ctime |
int64 | 创建时间 |
last_update_timestamp |
int64 | 最后更新时间 |
process_uid |
string | 处置人(D10 真值) |
process_time |
int64 | 处置时间(D10 真值) |
user_id |
string | 归属用户 |
非超管按
user_id强制过滤;越权读取返回 404。所需权限analytics.alert.view。
PATCH /api/analytics/alert/{id}/ack 请求
鉴权:analytics.alert.ack
输入:path id,body 可空。
输出:data 为 null。
6.10 业务健康(Health · Phase 3)
适用场景:分析业务可用性 + 源站质量 + 慢 URI + 地域质量。
| API | chart-key | 推荐图表 | 说明 |
|---|---|---|---|
GET /api/analytics/health/summary |
summary |
KPI 数字卡(6 个) | c2xx/c3xx/c4xx/c5xx/n4xx/n5xx 总数 |
GET /api/analytics/health/status-breakdown |
status-breakdown |
堆叠柱图(时序) | 状态码三层 c/n/a 拆分(c=客户端、n=网关、a=应用) |
GET /api/analytics/health/origin-errors |
origin-errors |
表格 / 横向 bar | 源站异常排行(ES upstream_addr terms,仅 upstream_status >= 500) |
GET /api/analytics/health/origin-latency |
origin-latency |
折线图(3 系列) | 源站时延(移动/联通/电信 平均时延) |
GET /api/analytics/health/slow-uri |
slow-uri |
表格 | 慢 URI TOP(第一版按命中次数 TOP;慢请求排序后续按真实耗时数据接入) |
GET /api/analytics/health/availability |
availability |
KPI / 多线折线 | HTTP/Ping/DNS/TCP/Page/IPv6 可用率 + 不可用时长 |
GET /api/analytics/health/geo-isp-quality |
geo-isp-quality |
表格 / 地图 | 地域/运营商质量 |
真值边界:percentile / p50 / p95 / p99 在 chart 与 statistic 包均无字段;时间窗 ≤ 24h 才走 ES 实时 percentile(D4)。可用性表
m_ava_domain.*AvailableDomain主键是domain_or_ip(不是domain_id)。
6.11 平台运维(Ops · Phase 5)
适用场景:平台级运营视角 — 看高流量/高错误用户和域名、源站异常、节点容量。
权限边界:
analytics.ops.view只读全平台数据,不允许传target_user_id切换视角;analytics.ops.admin才能切换。普通客户级账号即使有 view 也不能访问 ops。
| API | chart-key | 推荐图表 | 说明 |
|---|---|---|---|
GET /api/analytics/ops/summary |
summary |
KPI 数字卡(6 个) | 全平台容量摘要(请求/字节/峰值带宽/源站带宽/活跃域名/活跃用户) |
GET /api/analytics/ops/traffic-users |
traffic-users |
横向 bar / 表格 | 高流量用户 TOP(按 total_bytes DESC) |
GET /api/analytics/ops/traffic-domains |
traffic-domains |
横向 bar / 表格 | 高流量域名 TOP |
GET /api/analytics/ops/error-users |
error-users |
表格 | 高错误用户 TOP(按 c5xx DESC,含 c4xx/n5xx) |
GET /api/analytics/ops/error-domains |
error-domains |
表格 | 高错误域名 TOP |
GET /api/analytics/ops/origin-errors |
origin-errors |
表格 | 源站异常排行 |
GET /api/analytics/ops/nodes |
nodes |
表格 / 拓扑图 | 节点/机房视图(RPC GetWafIpWithMachineRoom + ES server_addr/bind_addr) |
GET /api/analytics/ops/query-pressure |
query-pressure |
折线图(占位) | ES 查询压力(依赖埋点,第一版返回 available:false) |
真值边界:节点系统指标(CPU/内存/磁盘)chart 不存,需走外部 zabbix。本期不实现。
node_id/server_node是禁字段。
6.12 处置闭环(Closure · Phase 6)
适用场景:在一个页面同时处理告警和风险队列;支持批量确认。
真值字段(D10):
process_uid/process_time/status/level。禁字段:handle_user/handle_time/risk_score/alert_status。AlertRecord.status (0/1/2/3) 与 RiskRecord.status (1/2) 语义不同,前端 i18n key 不可共用。
| API | 方法 | chart-key | 推荐图表 | 说明 |
|---|---|---|---|---|
GET /api/analytics/closure/summary |
GET | summary |
KPI 数字卡(5 个) | 待处理告警/风险数 + 已处置数 + 平均处置时长(ms) |
GET /api/analytics/closure/alerts |
GET | alerts |
表格(分页) | 待处理告警队列(status=0) |
GET /api/analytics/closure/risks |
GET | risks |
表格(分页) | 待处理风险队列(后续接 RiskRecord 表;当前无数据时返回空列表) |
GET /api/analytics/closure/trend |
GET | trend |
折线图 / 堆叠柱 | 处置历史趋势(按 ctime + status 分组) |
POST /api/analytics/closure/alerts/confirm |
POST | - | 不适合图表 | 批量确认告警(代理 /api/alert/records/confirm) |
POST /api/analytics/closure/risks/confirm |
POST | - | 不适合图表 | 批量确认风险(代理 /api/chart/risk/events/:event_id/confirm) |
summary 输出字段
{
"alerts_pending": 12,
"alerts_handled_today": 8,
"risks_pending": 0,
"risks_handled_today": 0,
"avg_handle_time_ms": 0
}
confirm 接口请求体
{
"ids": ["a1", "a2", "a3"],
"remark": "已加黑名单"
}
鉴权:analytics.closure.confirm
输出:data 为 null。
6.13 缓存收益(Cache · Phase 6)
适用场景:分析 CDN/边缘缓存对回源带宽的节省价值。
真值字段(D8):
total_cache_count/total_cache_bytes/total_cache_response_bytes。禁字段:cache_count/cache_bytes/cache_hit单字段命名(不存在)。
| API | chart-key | 推荐图表 | 说明 |
|---|---|---|---|
GET /api/analytics/cache/summary |
summary |
KPI 数字卡(4 个) | 命中率 / 节省回源字节 / 命中次数 / 平均缓存对象大小 |
GET /api/analytics/cache/trend |
trend |
折线图(双 Y 轴) | 命中率趋势(请求数 vs 缓存命中数) |
GET /api/analytics/cache/top-uri |
top-uri |
表格 / 横向 bar | URI TOP(命中次数/命中率/节省字节) |
GET /api/analytics/cache/content-types |
content-types |
饼图 | 内容类型分布(response_content_type 聚合) |
summary 输出字段
| 字段 | 类型 | 说明 |
|---|---|---|
hit_rate |
float | 缓存命中率 = total_cache_count / request_count |
saved_response_bytes |
int | 节省回源带宽(源站本应承担但缓存挡住的字节) |
total_cache_count |
int | 命中次数 |
total_cache_bytes |
int | 命中字节 |
avg_object_bytes |
float | 平均缓存对象大小 = total_cache_bytes / total_cache_count |
request_count |
int | 总请求数 |
业务化指标:
- 缓存命中率 =
total_cache_count / request_count - 节省回源带宽 =
total_cache_response_bytes - 平均缓存对象大小 =
total_cache_bytes / total_cache_count
6.14 原始日志(Logs · Phase 1)
原始日志是明细查询,不是图表单图接口;它使用统一鉴权方式,但请求/响应以列表、详情、导出为主。
| API | 方法 | 权限 | 推荐图表 | 说明 |
|---|---|---|---|---|
GET /api/analytics/logs |
GET | analytics.logs.view |
表格(分页 + 12 字段筛选) | 分页查询原始访问/攻击日志 |
GET /api/analytics/logs/{uuid} |
GET | analytics.logs.view |
详情卡片(7 区块) | 单条日志详情(basic/request/response/upstream/protection/waf_detail/ai_detail) |
POST /api/analytics/logs/export |
POST | analytics.logs.export |
不适合图表 | 字段白名单导出(csv/json,size ≤ 10000,超出走异步任务) |
GET /api/analytics/logs 筛选字段
12 字段筛选:uuid / session_id / remote_addr / host / uri / method / status / z_final_action / z_final_type / z_final_mod / z_final_action_type / z_white。
真值边界:
z_final_action整数枚举0=放行 / 1=拦截 / 2=验证码;z_white是独立 bool 字段(白名单命中),不参与 action 枚举。禁字段:match_content/match_area/hit_rule/rule_desc(chart 与 statistic 包均无)。
第一版兜底响应
第一版 stub 返回:
{ "available": false, "reason": "原始日志 ES 查询待接入..." }
列表/详情/导出契约稳定,后续接 ES zcloud-access-*。
6.15 报表中心(Reports · Phase 4)
报表中心是模板、生成、下载类接口,不使用单图响应结构。列表和详情仍使用统一 JSON 信封;下载接口返回文件流。
| API | 方法 | 权限 | 推荐图表 | 说明 |
|---|---|---|---|---|
GET /api/analytics/reports/templates |
GET | analytics.reports.view |
表格 / 卡片网格 | 模板列表(含 platform_only 标记) |
GET /api/analytics/reports |
GET | analytics.reports.view |
表格(分页) | 报表历史列表 |
GET /api/analytics/reports/{id} |
GET | analytics.reports.view |
详情卡片 | 单条报表详情(状态、参数、产物 URL) |
POST /api/analytics/reports/generate |
POST | analytics.reports.generate |
不适合图表 | 触发生成(platform-summary 模板需 analytics.reports.platform) |
GET /api/analytics/reports/{id}/download |
GET | analytics.reports.download |
不适合图表 | 下载产物(pdf/csv/json/html) |
模板枚举(D7):protection-value / asset-risk / attack-source / business-health / platform-summary(仅平台运维/超管) / raw-log-export。
异步阈值:预估行数 ≤ 100k 走同步;超出强制异步返回 task_id,前端轮询 /reports/:id 获取状态 + 下载链接。第一版同步生成超时 30 秒,超时降级为异步。
generate 请求体
{
"template": "protection-value",
"format": "pdf",
"window": "last_30d",
"stime": 1735660800000,
"etime": 1738339200000,
"filters": {}
}
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
template |
string | 是 | 模板名(D7 闭集) |
format |
string | 是 | pdf / csv / json / html |
window |
string | 否 | 时间窗别名 |
stime / etime |
int64 | 否 | 自定义时间戳 |
filters |
object | 否 | 模板专属筛选条件 |
6.16 CLI 对应关系
Analytics API 均由 zcloud analytics 命令适配:
# 原 6 page
zcloud analytics overview kpi --format json
zcloud analytics access status --window last_24h --format json
zcloud analytics protect waf/types --format json
zcloud analytics ai logs --page 1 --size 20 --format json
zcloud analytics bot session <session-id> --format json
zcloud analytics alert ack <alert-id>
# 2026-04-30 chart-rebuild 6 phase 扩展(13 条新命令)
zcloud analytics health summary --window last_24h --format json
zcloud analytics ops traffic-users --top 20 --format json
zcloud analytics closure summary --format json
zcloud analytics cache summary --format json
zcloud analytics logs list --window last_24h --status 403 --format json
zcloud analytics logs detail req-abc123 --format json
zcloud analytics logs export --format csv --fields ctime,uuid,host,uri,status > logs.csv
zcloud analytics closure alerts confirm --ids a1,a2,a3
zcloud analytics closure risks confirm --ids ev_001,ev_002
zcloud analytics reports templates --format json
zcloud analytics reports list --format json
zcloud analytics reports describe r-001 --format json
zcloud analytics reports generate --template protection-value --window last_30d --format pdf
zcloud analytics reports download r-001 --output report.pdf
后续如果新增 Analytics API,必须同步增加或确认已有 CLI 适配;如果只是新增 chart-key,至少要更新 CLI chart-key 清单与文档。
§7 套餐目录(Plan)
对外开放范围说明:仅以下两个只读接口对外开放,用于查询套餐目录。套餐的创建/编辑/删除、为用户开通、订阅查询,以及订单的续费/变更/退款/审核(
/api/plan/orders/*),均属平台控制台管理操作,直接操作在线计费数据,不在对外对接 API/CLI 范围(仅平台运维经控制台 + RBAC 使用)。
GET /api/plan/plans — 套餐列表(分页)
查询套餐目录,支持按产品类型和关键词过滤,分页返回。
所需权限:plan.plan.list
Query 参数
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
page |
int | 否 | 1 | 页码(从 1 开始) |
size |
int | 否 | 20 | 每页条数 |
prod_type |
int | 否 | 0 (全部) | 产品类型过滤:2=WAF · 4=Monitor · 32=GFIP |
keyword |
string | 否 | — | 套餐名称关键词模糊搜索 |
响应 data 字段
{
"list": [ { "plan_id": "...", "name": "基础版", "prod_type": 2, "price": 99.00, "valid": 365, "level": 1, "open_status": true, ... } ],
"total": 10,
"page": 1,
"size": 20
}
示例
# Bearer Session
curl -H "Authorization: Bearer $TOKEN" \
"$API/api/plan/plans?prod_type=2&keyword=基础&page=1&size=20"
# API Key
curl -H "Authorization: ApiKey zck_prefix.secret" \
"$API/api/plan/plans?prod_type=2"
GET /api/plan/plans/{id} — 套餐详情
按套餐 ID 查询单个套餐的完整信息(含 content 配额 JSON)。
所需权限:plan.plan.view
Path 参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
id |
string | 是 | 套餐 ID(UUID) |
响应 data 字段(PlanVO)
| 字段 | 类型 | 说明 |
|---|---|---|
plan_id |
string | 套餐唯一 ID(UUID) |
name |
string | 套餐名称 |
content |
object | 套餐配额 JSON(各产品类型对应字段不同) |
price |
float | 套餐价格(保留 2 位小数) |
scene |
string | 适用场景描述 |
comment |
string | 备注 |
open_status |
bool | 是否公开售卖 |
valid |
int64 | 有效期(天数) |
effect |
int32 | 生效方式 |
level |
int64 | 套餐等级 |
creator_id |
string | 创建者 ID |
ctime |
int64 | 创建时间(Unix 毫秒) |
utime |
int64 | 更新时间(Unix 毫秒) |
version |
string | 套餐来源版本(cloud / zmod) |
prod_type |
int32 | 产品类型(2=WAF 4=Monitor 32=GFIP) |
示例
curl -H "Authorization: Bearer $TOKEN" \
"$API/api/plan/plans/550e8400-e29b-41d4-a716-446655440000"
CLI 等价命令
zcloud plan list --prod-type 1 --keyword 基础版
zcloud plan describe <plan_id>
§8 节点安装 / 升级(Node Install)
用途:在防护节点主机上一键安装 / 升级 skynet-node。链路分两侧:管理面(平台登录态 + RBAC)注册安装包、生成一次性命令、查询任务、撤销 token;安装机侧(仅认安装 token)拉脚本、下载包/env、回报结果。
后端实现:src/backend/internal/node/{handler,service,repo}/install.go、路由src/backend/internal/node/route.go、回收任务src/backend/internal/app/install_reaper.go。
8.0 鉴权与状态码
| 维度 | 管理面接口 | 安装机侧接口 |
|---|---|---|
| 路径 | /install/artifacts /commands /upgrades /jobs /tokens/:id/revoke |
/install/script /package /env /report |
| 鉴权 | 平台统一登录态(Bearer Session / API Key)+ RBAC | 仅 Authorization: Bearer <install_token> |
RBAC action(perms.NodeNode) |
artifact / install / upgrade / job / revoke |
无(token 自鉴权) |
| 鉴权失败 | 401 / 403(平台统一信封) | 401,并带 WWW-Authenticate: Bearer realm="node-install"(challenge) |
要点:
- 安装 token 永远只在
Authorization头里传递,绝不进 URL query。 - 安装机侧四个接口鉴权失败统一返回
401+ challenge 头;/env在 token 有效但 env 载荷已不可用时返回403;/report的job_id与 token 绑定 job 不一致返回403。 - cloud 自有表口径固定
node_install_*(node_install_artifacts/node_install_tokens/node_install_jobs/node_install_reports),仅落guard_local,不写老库。
8.1 POST /api/node/install/artifacts — 注册本地安装包并预检
注册后端主机上已存在的安装包,扫描并计算 sha256、跑预检。
curl -sS -X POST https://<cloud>/api/node/install/artifacts \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"name":"skynet-node-1.0.0.tar.gz","version":"1.0.0","package_path":"/data/artifacts/skynet-node-1.0.0.tar.gz"}'
约束:
package_path必须是后端主机绝对路径,后缀.tar.gz/.tgz,且必须位于允许的 artifact 根目录之内。- 默认允许根目录为
/data/artifacts,/opt/cloud/artifacts(可用环境变量NODE_INSTALL_ARTIFACT_ROOTS覆盖,逗号分隔)。默认不含/tmp——/tmp全局可写,允许它会让任意本地进程投放 tarball 走注册流程;测试需要临时目录时必须显式设置NODE_INSTALL_ARTIFACT_ROOTS。 - 预检阻断项(
severity=error)未过 →status=failed;warning/info不阻断 →status=ready。阻断项含:VERSIONS清单、env.conf存在且无生产标记、必需 env key、必需 topic 提示、spoasig-*规则完整。binary_version_drift、pulsar_config_risk为warning,不阻断。
响应(节选,package_path 仅回文件名,不暴露后端绝对路径):
{"code":0,"data":{
"artifact_id":"8f1c…","name":"skynet-node-1.0.0.tar.gz","version":"1.0.0",
"sha256":"…64hex…","status":"ready",
"precheck":{"passed":true,"checks":[
{"key":"required_env","severity":"error","passed":true,"message":"required env keys found"},
{"key":"binary_version_drift","severity":"warning","passed":true,"message":"…"}
]}
}}
GET /api/node/install/artifacts 列出已注册包;列表里的 package_path 同样只展示文件名,前端/示例不要展示后端真实绝对路径。
8.2 POST /api/node/install/commands · POST /api/node/install/upgrades · POST /api/node/install/uninstalls — 生成一次性命令
curl -sS -X POST https://<cloud>/api/node/install/commands \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{
"artifact_id":"8f1c…",
"node_id":"可选-目标节点UUID",
"server_url":"https://<cloud>",
"ttl_seconds":3600,
"max_uses":20,
"env":{
"ZCLOUD_NGX_ACCESS_TOPIC":"cloud/ngx",
"ZCLOUD_CC_TOPIC":"cc/sync",
"ZCLOUD_SYNC_TOPIC":"zcloud-sync",
"ZCLOUD_DELTA_TOPIC":"zcloud-delta",
"ZCLOUD_BLOCK_TOPIC":"zcloud-block"
}
}'
升级命令用 /upgrades,等价于 action=upgrade,请求体相同。
卸载命令用 /uninstalls,等价于 action=uninstall,请求体相同(同 install/upgrade 的 artifact_id 必填、server_url 必填、env/ttl_seconds/max_uses 可选)。与升级一样作用于已有节点,node_id 必填(缺省 → 400「卸载必须指定目标节点」)。响应同样是一次性 command(curl … | sudo bash 一行,明文 token 只出现一次)。权限:node.node.uninstall。
⚠️ 破坏性、不可恢复:引导脚本据
GET /api/node/install/package返回的服务端权威响应头X-Install-Action(值取自 token 绑定 job 的动作,此处为uninstall)决定跑包内uninstall.sh而非install.sh,并用 here-string 自动应答其交互式[y/N]确认。uninstall.sh会停止并移除该节点上的全部防护服务(nginx / agent / waf-spoa 等)及其数据目录,操作不可恢复。范围:卸载只移除节点主机上的服务,不删除云端节点列表里的节点记录。如需同时清掉节点记录,运维另行调用
DELETE /api/node/nodes/:id。
响应:
{"code":0,"data":{
"job_id":"…","token_id":"…","token_prefix":"nit_xxxxxxx",
"expires_at":1735900000000,
"command":"curl -fsSL --connect-timeout 10 --max-time 60 -H 'Authorization: Bearer nit_…' 'https://<cloud>/api/node/install/script' | sudo bash -s -- --token 'nit_…' --server 'https://<cloud>'"
}}
约束 / 行为:
server_url必须匹配 cloud 配置的对外 base URL(scheme + host[:port])。否则 400 —— 防止特权调用方把攻击者控制的主机塞进安装命令(安装机会用 token 信任该主机的 package/env/report)。本地测试例外:配置允许 localhost 时,loopbackserver_url放行。server_url必须是绝对 URL,localhost 之外强制 https;query / fragment 会被丢弃。env是注册时设定的节点变量(env.conf 文本);留空则默认取包内env.conf。值做 shell 单引号转义后下发。- env key 采用 deny-list(非 allow-list):包是变量无关的,变量由上层在注册时给,故接受任意业务键(如
REG_URL/AGENT_PORT/PULSAR_ADDR等);仅当命中敏感词(PASSWORD/PASSWD/SECRET/PRIVATE/CRED/APIKEY/API_KEY/AUTH_TOKEN/ACCESS_TOKEN/ACCESS_KEY/SECRET_KEY/SIGNING_KEY/BOOTSTRAP_TOKEN,大小写不敏感)或疑似安装 token / Bearer 凭证时 → 400 且不创建 token / job。env 文本持久化到node_install_jobs.env_payload,以便后端重启 / 多副本时/install/env仍可重放。 AGENT_PORT(可选注册变量):设定后本次安装的 agent 以该端口监听 + 注册(默认33020),用于与同机已有 agent 错开端口。端口由 cloud 在 sha256 校验后注入解压出的安装脚本,包文件不被改动。ttl_seconds:默认3600,上限86400(24h)。max_uses:最低 5(低于 5 自动抬到 5)、默认20、上限100。建议保留重试余量(脚本下载 package + env 至少各消耗 1 次,失败重试还会再消耗),不要贴着最低值设。artifact.status != ready→ 400,不创建 token / job。- 明文 token 只在
command里出现一次;库中 token 仅存sha256哈希 + 12 位prefix。node_install_jobs.command只存脱敏模板(<redacted>),不含明文 token 或 Bearer 头。 job.spec只保留白名单字段(server_url/env_sha256/env_keys/artifact/token_prefix),env_payload在所有 job 响应里都被剥离。
8.3 安装机侧:script / package / env / report
command 拉取并执行的脚本(GET /install/script)会:set -euo pipefail + 退出清理临时目录 → 带 --connect-timeout/--max-time/--retry 下载 package、env → 校验 X-Artifact-SHA256 与本地 sha256sum 一致(不一致上报 failed 并退出)→ 用云端 env 覆盖包内 env.conf → 若注册变量含 AGENT_PORT 则注入解压出的 install*.sh(把 agent 监听/注册端口从默认 33020 改为该值,仅改解压副本,不动已校验包文件)→ 执行包内 install.sh → 经 /report 回报 running / success / failed。
token 配额语义(关键):
| 接口 | 鉴权方式 | 是否消耗 max_uses(use_count) |
计数 / 副作用 |
|---|---|---|---|
GET /install/script |
校验 token 有效性 | 否(ValidateBearerNoUse) |
不消耗,便于脚本可被重复拉取 |
GET /install/package |
校验并占用 | 是,use_count+1 |
响应头 X-Artifact-SHA256 / X-Install-Job-ID;job 置 running |
GET /install/env |
校验并占用 | 是,use_count+1 |
返回 env 文本;env 载荷不可用时 403 |
POST /install/report |
ValidateBearerForReport |
否 | 独立 report_count+1;不消耗 max_uses |
report用独立report_count计数,安装机多次回报(running→success/failed)不会耗尽max_uses。failed/running回报不关闭 token;只有success才把 token 置used(终态,后续不可用)。failed回报允许在已revoked的 token 上提交,以便被运维撤销的安装运行仍能把 job 收敛到failed。report若带job_id,必须与 token 绑定 job 一致,否则 403。job 已终态(success/failed)时滞后回报不覆盖终态。
安装机侧手动联调:
TOKEN=nit_xxx; BASE=https://<cloud>
curl -fsSL -H "Authorization: Bearer $TOKEN" "$BASE/api/node/install/script"
curl -fsSL -D - -o pkg.tar.gz -H "Authorization: Bearer $TOKEN" "$BASE/api/node/install/package"
curl -fsSL -H "Authorization: Bearer $TOKEN" "$BASE/api/node/install/env"
curl -fsS -X POST "$BASE/api/node/install/report" \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"status":"success","message":"done","hostname":"node-1","node_version":"1.0.0"}'
8.4 GET /api/node/install/jobs · /jobs/:id — 查询任务
curl -sS -H "Authorization: Bearer $TOKEN" https://<cloud>/api/node/install/jobs # 最近 50 条
curl -sS -H "Authorization: Bearer $TOKEN" https://<cloud>/api/node/install/jobs/<job_id> # 含 reports[]
status:pending → running → success / failed。started_at / finished_at 为毫秒时间戳,0 表示未发生。详情接口附最近 reports(最多 20 条)与 recent_report。
8.5 POST /api/node/install/tokens/:id/revoke — 撤销 token
curl -sS -X POST -H "Authorization: Bearer $TOKEN" \
https://<cloud>/api/node/install/tokens/<token_id>/revoke
- 仅能撤销仍
active的 token;已used/revoked返回 400。 - 撤销后安装机侧 script/package/env 立即 401;
failed回报仍可提交以收敛 job。 - token 不落单独的
expired状态,过期统一由expires_at派生;status=active仅表示未撤销/未使用,不等于"仍可用"。
8.6 Stale job 回收(reaper)
后端单进程后台扫帚 install_reaper.go:启动时立即跑一次,之后每 10m 一次。把 ctime 早于 now - 24h(StaleJobMaxAge)且仍处于 pending/running 的 job 原子置为 failed(finished_at=now、message="install job timed out without report"),并在同一事务内 revoke 指向这些 job 的仍 active 的 token —— 防止被强杀的安装机事后再用 bearer token 复活已关闭的 job。终态 job 不会被改写;多副本下事务 WHERE 子句保证幂等(仅首个进程命中,其余 RowsAffected=0 静默退出)。
8.7 前端展示约定
- 生成命令的明文 token 只展示一次;UI 须提示"仅显示一次、请立即复制保存"。
- 列表/详情只显示
token_prefix(如nit_xxxxxxx)与状态,绝不回显明文 token。 - 复制命令后清空剪贴板(设定超时后清除),避免 token 长期驻留剪贴板。
- artifact 列表不展示后端真实
package_path绝对路径(后端已只回文件名)。
8.8 POST /api/node/reg — 节点 agent 自注册
节点 agent 自注册端点。公共端点:不挂 RBAC、不需要 Bearer 鉴权,与 POST /api/node/install/report 同类(属 agent 基础设施,无 zcloud CLI 命令)。唯一访问门槛是请求体里的共享口令 dummy_token——必须等于 agent 端硬编码的固定常量值,不匹配即拒绝。
后端实现:
src/backend/internal/node/{handler,service}/reg.go、路由src/backend/internal/node/route.go(rg.POST("/reg", h.RegNode))。
请求体字段(注意 manger_addr 是 agent 既有拼写,缺 a,不能改成 manager_addr):
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
node_id |
string | 否 | 首次安装为空;非空表示 agent 已持有节点 ID(命中既有节点则复用,不新建) |
manger_addr |
string | 是 | 管理地址 host:port,agent 用 ip route get 自动探测后上报。端口缺失时回落默认端口 33020 |
node_type |
string | 否 | proto 枚举名字符串,如 "NODE_1_WAF"。仅支持 WAF 防护节点(空 / "NODE_1_WAF" / "waf" / "1" 均映射为 WAF,其它值返回非零 code) |
extend_config |
string | 否 | url-escape 后的扩展配置,自注册暂不消费 |
dummy_token |
string | 是 | 共享口令,必须等于 agent 硬编码的固定常量值,否则拒绝 |
plugin |
string | 否 | 插件列表,如 "waf,detect,agent,ebpf" |
only_acl |
bool | 否 | 仅 ACL 模式标记,自注册节点不走该路径 |
ip |
string | 否 | only_acl 关联参数,标准注册为空 |
acl_tags |
string | 否 | only_acl 关联参数 |
ip_groups |
string | 否 | only_acl 关联参数 |
curl -sS -X POST https://<cloud>/api/node/reg \
-H 'Content-Type: application/json' \
-d '{
"node_id":"",
"manger_addr":"192.168.14.171:33020",
"node_type":"NODE_1_WAF",
"dummy_token":"<agent 硬编码共享口令>",
"plugin":"waf,detect,agent,ebpf"
}'
响应:标准信封 {code, message, data},data 为 RegNodeResponse:
{"code":0,"message":"success","data":{
"node_id":"3f2c…",
"listen_addr":":33020",
"tls":false,
"cert":"",
"key":"",
"settings":{},
"plugin":{}
}}
| 响应字段 | 类型 | 说明 |
|---|---|---|
node_id |
string | 节点 ID。幂等命中既有节点时返回既有 ID;首次注册返回新建 ID |
listen_addr |
string | 监听地址,形如 ":33020",取自管理地址端口(缺失回落默认 33020) |
tls |
bool | 新平台(NSQ)固定 false(不再用 etcd 下发每节点证书) |
cert |
string | 新平台返回空串 |
key |
string | 新平台返回空串 |
settings |
object | 下发配置。新平台配置走 NSQ 发布订阅,固定返回空映射 {} |
plugin |
object | 插件配置。新平台固定返回空映射 {} |
语义要点:
- 幂等(按管理地址 upsert):同一
manger_addr重复注册返回相同node_id,绝不新建重复节点;新老 agent 共存时保留既有节点,不覆盖其字段。 - 首次注册:创建一条节点记录(
machine_room默认值为default,运维可在节点列表里改归到真实机房),并以管理 IP 派生落一条ip_addr记录——于是节点自动出现在节点列表,管理地址与业务 IP 都已自动填好。落ip_addr为尽力而为:IP 已被占用等非致命错误不影响注册成功。 - 失败处理:始终返回 HTTP
200,业务错误通过响应体非零code表达。dummy_token不匹配、manger_addr缺失或非法、node_type非 WAF 类型均返回非零code并附带错误消息。
§A Analytics 通用查询参数
适用于所有单图 GET 接口(GET /api/analytics/<page>/<chart>)。未传参数时后端使用默认值;传入无权限的 target_user_id 或跨 OEM 资源时返回 403。
| 参数 | 类型 | 必填 | 取值/示例 | 说明 |
|---|---|---|---|---|
window |
string | 否 | last_1h / last_24h / last_7d |
时间窗口别名;为空时后端默认 last_24h |
stime |
int64 | 否 | 1746748800000 |
自定义起始时间 Unix 毫秒(与 etime 配对,比 window 优先级高) |
etime |
int64 | 否 | 1746835200000 |
自定义结束时间 Unix 毫秒 |
site_id |
string | 否 | site-001 |
站点过滤 |
domain_id |
string | 否 | d_8a3b1c |
域名过滤 |
target_user_id |
string | 否 | u-tenant-001 |
客户级切换被查看用户;后端统一做越权校验 |
compare |
bool | 否 | false |
是否启用上一周期对比(仅部分 chart 支持) |
top |
int | 否 | 10 |
TopN,默认 10,最大 100 |
order |
string | 否 | bytes_desc |
排序方式,具体含义由图表定义(如 top-url 支持 request_count_desc/bytes_desc/cache_desc) |
page |
int | 否 | 1 |
列表类图表分页 |
size |
int | 否 | 20 |
列表类分页每页条数,最大 100 |
单图响应骨架:
{
"code": 0,
"message": "ok",
"data": {
"chart_key": "access/status",
"render_hint": "categorical_distribution_over_time",
"schema": {
"dimensions": [
{ "name": "status_class", "type": "enum", "values": ["2xx", "3xx", "4xx", "5xx"] },
{ "name": "time", "type": "timestamp", "unit": "ms" }
],
"measures": [
{ "name": "count", "type": "integer", "unit": "requests" }
]
},
"rows": [],
"meta": {
"cache": "miss",
"source": "postgres",
"latency_ms": 12,
"window": {
"stime": 1777526400000,
"etime": 1777530000000,
"granularity": "5m",
"bucket_table": "tfs_flow_domains"
}
}
}
}
window.granularity是响应字段,描述实际命中的聚合粒度(5m / 1h / 1d),不是用户输入参数。客户传window=last_24h,后端按窗口大小自动选表。
§B 可视化建议总表
B.1 Chart 统一契约 — render_hint 速查
所有 chart-key 由前端按 render_hint 自动分发到 6 个 chart 组件之一。这是契约真值(docs/specs/chart-contract.md §2),不可自创新词。
render_hint |
schema 形状 | 推荐前端组件 | 典型场景 |
|---|---|---|---|
kpi |
0~1 dim + 1+ measure | KpiGroupCard |
多指标数字卡组(如 overview/kpi 的 6 测度) |
categorical_distribution |
1 categorical dim + 1 measure | PieCard(≤8 类)/ BarCard(>8 类) |
一维占比(如 overview/event-type) |
categorical_distribution_over_time |
1 categorical + 1 timestamp + 1 measure | StackedBarCard / LineCard 多 series |
多分类按时间堆叠(如 access/status) |
time_series_single |
1 timestamp + 1 measure | LineCard |
单测度时序(如 access/request-hm 无 compare) |
time_series_multi |
1 timestamp + ≥2 measures,或 1 categorical + 1 timestamp + 1 measure | LineCard 多线 |
多测度时序(如 access/flow-hm 5 测度);compare 走子形态 B |
topn |
1 string dim + 1 measure | BarCard 横向 / RankingCard |
已排序 TOP-N(如 protect/waf/top-ip) |
geo |
1 geo dim + 1 measure | GeoHeatmapCard |
地理分布(如 protect/waf/geo) |
table |
任意 | TableCard |
不适合可视化的兜底 |
新增 hint 词汇必须双方评审通过(cloud + Aegeon),不可单边扩词汇表。
B.2 数据形态速查
下表把"输出数据形态 → 推荐图表"的映射汇总在一起,对接前端时可作为速查表。实际响应仍以 Chart 统一契约的 schema + rows 为准。
| 数据形态 | 典型字段示例 | 推荐图表 | 不推荐 |
|---|---|---|---|
| 单值(标量) | {count: 12345} |
KPI 数字卡 | 折线 / 饼图 |
| 多 KPI(4-6 个标量) | {domain_count, requests, blocked, block_rate, qps} |
多 KPI 卡阵 / 雷达图 | 单饼图 |
| 时序单系列 | [{ctime, value}, ...] |
折线图 / 面积图 | 饼图 |
| 时序多系列 | [{ctime, requests, attacks}, ...] |
多线折线 / 堆叠面积 | 饼图 |
| 时序对比(compare) | {current:[...], previous:[...]} |
双线对比折线(实虚线) | 单折线 |
| 维度分布(少类 ≤ 8) | [{key, count}, ...] |
饼图 / 环形图 | 表格 |
| 维度分布(多类 > 8) | [{key, count}, ...] |
横向 bar / 柱图 | 饼图(碎片化) |
| 地理分布 | [{region, count}, ...] |
中国/世界地图热力 | 表格 |
| 排行 TOP | [{key, count, ...}, ...] |
横向 bar / 表格(含明细列) | 折线 / 饼图 |
| 二维矩阵 | [[v11, v12], [v21, v22]] |
热力图 | 折线 |
| 散点 | [{x, y, size, ...}, ...] |
散点图 / 气泡图 | 饼图 |
| 列表分页 | {list, total, page, size} |
表格(分页) | 任何图表 |
| 时间线明细 | {items: [{ctime, ...}]} |
时间线(vertical timeline) | 饼图 |
| 占位 | {available: false, ...} |
不渲染图表,渲染 n-empty 占位卡片 |
假数据 |
配色建议:
- 防护类(攻击/拦截):红色系(#ff4d4f / #ff7875)
- 流量类(请求/带宽):蓝色系(#2563eb / #60a5fa)
- 缓存/AI 类(增益):绿色系(#10b981 / #34d399)
- 中性指标:灰/紫色系(#6b7280 / #8b5cf6)
§C 相关文档
- 认证说明 — Bearer 会话、API Key 与 401 重试
- 示例代码 — 三语言调用示例(curl / Python / Go)
- 权限矩阵 — 接口对应的权限 key 与 OEM 隔离规则
- CLI 工具 — 等价的 CLI 操作
- 错误码 — 完整业务错误码表
- 快速上手 — 5 分钟跑通第一次调用
- /api/openapi.json — OpenAPI v3 完整 schema(机器读取)
- /llms.txt / /llms-full.txt — AI agent 速读入口
完整 API 索引
REST 全集导出为 OpenAPI v3:
GET /api/openapi.json
可直接导入 Postman / Insomnia / Swagger UI。所有路由含完整 schema、参数、响应示例与所需权限 key。
Cloud WAF · REST API Documentation · 完整索引以 /api/openapi.json 为准