API 集成实践
替代前端把 NIE-SLA 当作无凭据、只读、可缓存的数据源。不代理或复用 Admin Session,不直接调用未版本化的内部路由。
初始化顺序
- 规范化用户输入,只保留 Worker
origin。 - 请求
GET /api/v1,验证api_version === "v1"。 - 从 Manifest 的
endpoints与能力字段决定可用功能。 - 首屏请求
/api/v1/status?days=30&lite=1。 - 用户打开详情时再请求 checks、metrics、pings 或 latency。
- 页面隐藏时暂停轮询,恢复时加随机延迟。
最小客户端
js
export function createNieSlaClient(input) {
const base = new URL(input)
if (base.username || base.password) throw new Error('API 地址不能包含账号或密码')
if (base.protocol !== 'https:' && !['localhost', '127.0.0.1', '[::1]'].includes(base.hostname)) {
throw new Error('生产 API 必须使用 HTTPS')
}
const origin = base.origin
async function get(path, params = {}, timeoutMs = 12_000) {
const url = new URL(`/api/v1/${path}`.replace(/\/$/, ''), origin)
for (const [key, value] of Object.entries(params)) {
if (value !== undefined && value !== null && value !== '') url.searchParams.set(key, String(value))
}
const controller = new AbortController()
const timer = setTimeout(() => controller.abort(), timeoutMs)
try {
const response = await fetch(url, {
signal: controller.signal,
credentials: 'omit',
headers: { accept: 'application/json' },
})
const body = await response.json().catch(() => null)
if (!response.ok || body?.ok === false) throw new Error(body?.error || `HTTP ${response.status}`)
return body
} finally {
clearTimeout(timer)
}
}
return {
manifest: async () => {
const body = await get('')
if (body?.api_version !== 'v1') throw new Error('响应不是 NIE-SLA v1 Manifest')
return body
},
status: options => get('status', { days: 30, lite: 1, ...options }),
checks: (targetId, options) => get('checks', { target_id: targetId, ...options }),
metrics: (agentId, options) => get('metrics', { agent_id: agentId, ...options }),
pings: (agentId, options) => get('pings', { agent_id: agentId, ...options }),
latency: (targetId, options) => get('latency', { target_id: targetId, ...options }),
}
}示例同时检查 HTTP 状态与 body.ok,因为兼容接口可能在 HTTP 200 中返回业务错误。生产项目还应校验关键字段类型,并为 AbortError 显示超时状态。
React/Vue 状态模型
不要把一切合并成单一 loading 布尔值,至少区分:
ts
type ResourceState<T> =
| { state: 'idle' }
| { state: 'loading'; previous?: T }
| { state: 'ready'; data: T; warnings: string[] }
| { state: 'empty'; data: T; message: string }
| { state: 'error'; error: string; retryAt?: number }刷新时保留 previous 避免图表闪空;warnings[] 是部分数据退化,不覆盖已经成功的主体数据。
轮询与缓存
- Status 建议 20–60 秒;尊重
Cache-Control,优先观察X-NIE-SLA-Cache(v1 同时保留X-NStatus-Cache)。 - Manifest 默认可缓存 300 秒;Metrics 默认 15 秒;Pings 默认 20 秒;Latency 默认 30 秒。
- Checks 把规范化的
target_id、hours、limit纳入缓存键。 - 429 与 5xx 使用有上限的指数退避;400/403/404 不原样重试。
- 不添加随机查询参数绕过 Worker/Cloudflare 缓存。
图表数据
- 时间序列按时间戳显式升序,不依赖响应顺序。
ok = false的延迟是断点或故障标记,不能画成0 ms。format=columns需要检查dt与每个 values 数组长度。history_downsampled或pings_downsampled为真时说明数据已降采样。- Cloudflare Checks、Agent Pings 与外部 Latency 使用不同图例与来源标签。
- 温度、GPU 等可选字段缺失时隐藏系列,不补零。
服务端集成
服务端请求不受浏览器 CORS 约束,但仍受速率限制。使用共享缓存、合理 User-Agent、超时与有限重试;不要为每个终端用户请求重新抓取全部历史。公开 API 不提供写入能力,也不应在服务端保存管理员或 Agent 凭据来绕过边界。
浏览器安全
- fetch 固定
credentials: 'omit'。 - API Base 来自部署配置或经过验证的用户输入,不接受 URL 查询参数静默覆盖生产地址。
- 只允许 HTTPS Origin,开发时例外允许本机 HTTP。
- API 文本用框架默认转义或
textContent。 - 不把完整响应写入公开错误遥测,其中可能包含部署者主动公开但仍具识别性的节点资料。