消息协议
Canvas 主题运行在 opaque-origin sandbox iframe 中。宿主通过 postMessage 发送脱敏公开数据;主题通过固定消息类型声明就绪、请求高度与读取白名单公开资源。插件运行时当前未开放。
协议表
| 方向 | 类型 | 用途 |
|---|---|---|
| Canvas → 宿主 | nie-sla:ready | 请求发送当前状态 |
| 宿主 → Canvas | nie-sla:status | 完整公开状态快照 |
| Canvas → 宿主 | nie-sla:resize | 请求调整 iframe 高度 |
| Canvas → 宿主 | nie-sla:request | 请求白名单公开资源 |
| 宿主 → Canvas | nie-sla:response | 返回请求结果或错误 |
类型名与 Manifest Schema nie-sla-theme-v1 是当前协议常量,按字面使用。
就绪
js
parent.postMessage({ type: 'nie-sla:ready' }, '*')在消息监听器注册完成后发送。宿主也会在 iframe load 时尝试发送一次状态,主题必须接受重复快照。
状态快照
js
{
type: 'nie-sla:status',
api_version: 'v1',
payload: { /* 与 GET /api/v1/status 一致 */ }
}接收端校验:
js
window.addEventListener('message', event => {
if (event.source !== parent) return
if (!event.data || typeof event.data !== 'object') return
if (event.data.type !== 'nie-sla:status') return
if (event.data.api_version !== 'v1') return
render(event.data.payload)
})调整高度
js
parent.postMessage({
type: 'nie-sla:resize',
height: document.documentElement.scrollHeight
}, '*')非有限值回到默认;宿主最终限制为 400–12000。
历史请求
js
{
type: 'nie-sla:request',
request_id: 'checks-vps-a-72h',
resource: 'checks',
query: { target_id: 'vps-a', hours: 72, limit: 864 }
}字段规则:
request_id必填,最长 80 字符,调用方负责避免并发冲突。resource只允许status、checks、metrics、pings、latency。query最多读取前 20 个键。- 键只能是字母开头的字母、数字、下划线,最长 40 字符。
- 值仅接受 string、number、boolean,转换后最长 200 字符。
成功与失败响应
js
{
type: 'nie-sla:response',
api_version: 'v1',
request_id: 'checks-vps-a-72h',
ok: true,
payload: { /* 对应 v1 端点响应 */ }
}js
{
type: 'nie-sla:response',
api_version: 'v1',
request_id: 'checks-vps-a-72h',
ok: false,
error: 'HTTP 429'
}主题按 request_id 关联 Promise,设置超时,并在 iframe 销毁时清理待处理请求。错误文字只用于显示或日志摘要,不能作为 HTML。
宿主会忽略无效键、复杂查询值与超过前 20 个的查询项,不会传递至 API。主题不得把过滤行为当成输入验证;调用前仍按各端点文档约束参数。
为什么用 *
没有 allow-same-origin 的 iframe 具有 opaque Origin,宿主无法为 targetOrigin 指定普通网站 Origin。发送端用 *;接收端通过 event.source === parent 验证来源,并严格限制消息类型与能力。
生命周期
宿主可能在 iframe load 与收到 nie-sla:ready 时各发送一次状态,主题渲染必须幂等。切换或停用主题会销毁旧 iframe;旧窗口的迟到响应不得更新新主题状态。为每个挂载实例创建独立请求表,并在 pagehide 或卸载时清理计时器。