消息协议
Canvas 主题和插件都运行在 opaque-origin sandbox iframe 中。宿主通过 postMessage 发送脱敏公开数据;扩展通过固定消息类型声明就绪和请求高度。
协议表
| 方向 | 类型 | Canvas 主题 | 插件 | 用途 |
|---|---|---|---|---|
| 扩展 → 宿主 | nstatus:ready | 是 | 是 | 请求发送当前状态 |
| 宿主 → 扩展 | nstatus:status | 是 | 是 | 完整公开状态快照 |
| 扩展 → 宿主 | nstatus:resize | 是 | 是 | 请求调整 iframe 高度 |
| Canvas → 宿主 | nstatus:request | 是 | 否 | 请求白名单公开资源 |
| 宿主 → Canvas | nstatus:response | 是 | 否 | 返回请求结果或错误 |
这些类型名与 Manifest schema 是 v1 兼容性线协议常量,必须按字面使用。
就绪
js
parent.postMessage({ type: 'nstatus:ready' }, '*')扩展应在消息监听器注册完成后发送。宿主也会在 iframe load 时尝试发送一次状态,因此扩展必须接受重复快照。
状态快照
js
{
type: 'nstatus: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 !== 'nstatus:status') return
if (event.data.api_version !== 'v1') return
render(event.data.payload)
})调整高度
js
parent.postMessage({
type: 'nstatus:resize',
height: document.documentElement.scrollHeight
}, '*')非有限值会回到默认值;宿主最终限制插件为 200–1200,Canvas 主题为 400–12000。
Canvas 历史请求
js
{
type: 'nstatus: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: 'nstatus:response',
api_version: 'v1',
request_id: 'checks-vps-a-72h',
ok: true,
payload: { /* 对应 v1 端点响应 */ }
}失败响应
js
{
type: 'nstatus:response',
api_version: 'v1',
request_id: 'checks-vps-a-72h',
ok: false,
error: 'HTTP 429'
}扩展应按 request_id 关联 Promise,设置超时,并在 iframe 销毁时清理待处理请求。错误文字只用于显示或日志摘要,不能作为 HTML。
为什么发送使用 *
没有 allow-same-origin 的 iframe 具有 opaque Origin,宿主无法为 targetOrigin 指定一个普通网站 Origin。因此发送端使用 *;接收端通过保存的 contentWindow 或 event.source === parent 验证消息来源,并严格限制消息类型和能力。