4.9 KiB
4.9 KiB
Webhook 回调
NovaIx 在异步任务完成或失败时,会向集成方(Integration)配置的 callback_url 发送 POST 请求。
关于配置位置:
callback_url和callback_secret属于 Integration(不是 API Key)。API Key 只是访问凭证,可以轮换;集成方身份和回调配置保持稳定。详见 Provisioning API → 集成方与认证。
触发时机
| 任务类型 | 何时触发 |
|---|---|
| 创建实例 | 实例创建成功 / 失败 |
| 删除实例 | 实例完成删除 / 删除失败 |
| 启停/重启 | 操作完成 / 失败 |
| 重装系统 | 重装完成 / 失败 |
| 重置密码 | 操作完成 / 失败 |
| 暂停/解除暂停 | 操作完成 / 失败 |
只有通过 Provisioning API 创建的实例(带 external_id 和 integration_id)才会触发 webhook。管理员在后台直接创建的实例不会通知。
请求格式
POST https://your-billing.example.com/callback HTTP/1.1
Content-Type: application/json
X-Novaix-Signature: 7f3c5a2e9b1d...
Body:
{
"event": "task.completed",
"task_id": 100,
"task_type": "create_instance",
"external_id": "your_service_id_123",
"status": "completed",
"result": "",
"data": {
"ip_address": "103.25.60.15",
"ipv6_address": "2001:db8::1",
"hostname": "web-01"
},
"timestamp": 1748707200
}
| 字段 | 类型 | 说明 |
|---|---|---|
event |
string | task.completed 或 task.failed |
task_id |
int | NovaIx 内部任务 ID |
task_type |
string | 任务类型,如 create_instance、delete_instance、start_instance 等 |
external_id |
string | 集成方传入的服务 ID |
status |
string | completed 或 failed |
result |
string | 失败时的错误描述(成功时为空) |
data |
object | 仅创建成功时附带,包含 IP、hostname 等 |
timestamp |
int | Unix 时间戳(秒) |
验签
NovaIx 在 X-Novaix-Signature 头中发送 HMAC-SHA256(body, callback_secret) 的 hex 编码。
接收端必须验证签名,否则攻击者可以伪造任务完成通知导致服务被错误标记为已开通。
验证步骤
- 取出
X-Novaix-Signature头的值 - 用 Integration 关联的
callback_secret(创建 Integration 或轮换时一次性返回)对原始请求体做 HMAC-SHA256 - 用恒定时间比较函数(不要直接
==)对比两个签名是否相等
⚠️ 安全注意
- 必须用原始 body:不要解析后再签名,序列化结果可能不一致
- 必须用恒定时间比较:避免时序攻击(PHP
hash_equals、Pythonhmac.compare_digest、Nodecrypto.timingSafeEqual) - HTTPS-only:
callback_url必须用 HTTPS,否则签名密钥在传输中可能泄露 - 幂等处理:NovaIx 会重试 3 次(间隔 5s/10s/15s),接收端要对同一
task_id做幂等处理
重试策略与可靠性
⚠️ Webhook 是 best-effort 投递,不是可靠交付。集成方必须用主动轮询作为兜底。
NovaIx 端的局限:
| 失败场景 | 现状 |
|---|---|
| 接收端瞬时故障 | 最多重试 3 次,间隔 5s/10s/15s |
| 重试耗尽 | 不再发送,事件永久丢失 |
| 任务完成时 NovaIx 进程崩溃 | webhook 未发送,永久丢失 |
| 任务完成瞬间并发量爆增 | 调度并发达 32 上限时当场丢弃,不进入重试队列 |
| API Key 被删除后任务才完成 | webhook 不会发送(找不到回调地址) |
集成方必须做的:
- 关键状态确认走任务轮询:
suspend/unsuspend/terminate/reinstall/reset-password调用后用GET /provision/tasks/{id}等待最终状态,不要依赖 webhook - 创建实例:用
GET /provision/instances/{id}/status轮询running/error作为终态判定 - 定期对账:每天用
GET /provision/instances拉取所有实例状态,与自己计费侧对比
NovaIx 后续版本可能引入持久化重试队列让 webhook 升级为可靠交付,届时会通过文档更新通知。在那之前,请把 webhook 视为"通知方便",而不是"状态来源"。
接收端实现示例
故障排查
| 现象 | 可能原因 |
|---|---|
| 收不到任何 webhook | API 密钥没配 callback_url;或网络隔离访问不通 |
| 签名验证总失败 | 用了 JSON 解析后的字符串而不是原始 body;密钥用错(每个 API 密钥的 callback_secret 不同) |
收到的 external_id 为空 |
不应该出现——失败时 NovaIx 同步快照 external_id 后才清空。如果出现请检查 NovaIx 版本 |
创建成功但 data 中 ip_address 为空 |
节点没配置 IP 池,或 IP 池已耗尽。检查 NovaIx 后台节点配置 |