Webhook 格式

如果你通过 webhook 订阅,收到的内容格式如下:

添加或更新事件时:

{
"meta": {
"unsubscribe": "",
"documentation": ""
},
"page": {
"id": "",
"status_indicator": "",
"status_description": "",
"url": ""
},
"incident": {
"backfilled": false,
"created_at": "",
"impact": "",
"name": "",
"resolved_at": "",
"status": "",
"updated_at": "",
"id": "",
"url": "",
"incident_updates": [
{
"id": "",
"incident_id": "",
"body": "",
"status": "",
"created_at": "",
"updated_at": ""
}
]
}
}

添加或更新维护时:

{
"meta": {
"unsubscribe": "",
"documentation": ""
},
"page": {
"id": "",
"status_indicator": "",
"status_description": "",
"url": ""
},
"maintenance": {
"backfilled": false,
"created_at": "",
"impact": "",
"name": "",
"resolved_at": "",
"status": "",
"updated_at": "",
"id": "",
"url": "",
"duration": "",
"maintenance_updates": [
{
"id": "",
"maintenance_id": "",
"body": "",
"status": "",
"created_at": "",
"updated_at": ""
}
]
}
}

组件更新时:

{
"meta": {
"unsubscribe": "https://<status-page-domain>/unsubscribe?id=${subscriber.id}&token=${subscriber.unsubscribeToken}",
"documentation": ""
},
"page": {
"id": "",
"status_indicator": "",
"status_description": "",
"url": ""
},
"component_update": {
"created_at": "",
"new_status": "",
"component_id": ""
},
"component": {
"created_at": "",
"id": "",
"name": "",
"status": ""
}
}

可能的状态页状态:

  • UP
  • HASISSUES
  • UNDERMAINTENANCE

可能的组件状态:

  • OPERATIONAL
  • UNDERMAINTENANCE
  • DEGRADEDPERFORMANCE
  • PARTIALOUTAGE
  • MAJOROUTAGE

可能的事件状态:

  • INVESTIGATING
  • IDENTIFIED
  • MONITORING
  • RESOLVED

可能的维护状态:

  • NOTSTARTEDYET
  • INPROGRESS
  • COMPLETED

Webhook 负载校验

强烈建议在 webhook 端点中校验负载。

我们用一个密钥对 webhook 负载签名,并把签名放在名为 x-instatus-webhook-signature 的请求头中。这个签名让你可以验证该 webhook 确实来自 Instatus。

校验 Webhook 的步骤

  1. 保存你在订阅 webhook 时生成的 Webhook Secret(在为某个页面订阅 webhook 时可以看到,也可以在那里自定义它)。
Webhook 密钥
  1. 在你的服务器上创建一个接收该 webhook 的新端点。

  2. 把收到的签名与服务器生成的签名进行比较来校验。

  3. 如果签名一致,就处理这个 webhook。

代码示例

import crypto from 'crypto'
import express from 'express'
const app = express()
app.use(express.json())
const WEBHOOK_SECRET = 'your-webhook-secret'
function isVerifiedPayload(payload, signature, secret) {
const hmac = crypto.createHmac('sha256', secret)
const digest = hmac.update(JSON.stringify(payload)).digest('hex')
return crypto.timingSafeEqual(Buffer.from(digest), Buffer.from(signature))
}
app.post('/endpoint/to/webhook', (req, res) => {
const payload = req.body
const signature = req.header('x-instatus-webhook-signature')
if (!signature) {
return res.status(400).send('Signature missing')
}
if (!isVerifiedPayload(payload, signature, WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature')
}
// Process the valid webhook
res.status(200).send('Webhook received')
})
app.listen(3000, () => console.log('Server running on port 3000'))

为什么校验很重要

  • 确保真实性:保证该 webhook 确实来自我们的平台。
  • 防止篡改:能发现负载被改动过。
  • 提升安全性:防范重放攻击和未授权访问。