跳转至

故障Webhook推送


Webhook 用于将故障的关键变化推送到第三方系统。您可以将故障信息接入 ITSM、自动化平台或内部业务系统,由第三方根据收到的数据继续创建工单、同步状态或触发自动化流程。

故障中心 > 配置管理 > Webhook中可创建和管理 Webhook。

使用前提

请先准备一个能够接收 POST 请求的第三方地址。Webhook 支持 HTTP 和 HTTPS 地址;建议在生产环境使用 HTTPS。出于安全考虑,不能配置内网、回环或本机地址。

配置 Webhook

  1. Webhook页面点击新建 Webhook
  2. 填写名称和第三方接收 URL;
  3. 选择需要推送的故障事件: | 事件 | 说明 | | --- | --- | | 故障创建 | 新故障创建时推送。 | | 状态变化 | 故障状态发生变化时推送。 | | 等级变更 | 故障等级发生变化时推送。 | | 处理人变化 | 故障处理人发生变化时推送。 | | 聚合变更 | 聚合故障关联事件发生变化时推送。仅对通过故障聚合规则生成的故障生效。 |
  4. 点击生成 Token。Token 仅由 观测云 平台生成,请立即复制并安全保存到第三方接收服务的密钥配置中;
  5. 设置启用状态并保存。
注意
  • Token 是 Webhook 的认证密钥。生成后平台仅展示一次明文,后续页面仅显示脱敏值;重新生成 Token 会使旧 Token 立即失效;
  • Webhook 投递失败不会影响故障的创建、更新、恢复和关闭;
  • Webhook 使用固定请求方式、鉴权方式和超时时间,无需额外配置。

测试发送

保存 Webhook 后,可在该 Webhook 的操作项中点击测试并选择事件类型。系统会按正式请求格式发送一条测试数据,Payload 中的 isTesttrue

测试结果可在发送历史中查看。测试发送不影响真实故障,也不会计入正式发送统计。

请求协议

系统以 POST 方式发送 JSON 数据,请求超时时间为 5 秒,不跟随重定向。接收服务返回任意 2xx 状态码即视为投递成功。

Header 说明
Content-Type 固定为 application/json
Authorization 固定格式为 Bearer <Token>
X-Incidents-Event-Id 本次投递的唯一标识,可用于接收端幂等处理。
X-Incidents-Timestamp Unix 秒级时间戳。
X-Incidents-Signature HMAC-SHA256 签名,格式为 v1=<signature>

Payload 示例

{
  "eventId": "evt_01JXYZ...",
  "eventTypes": [
    "incident.created",
    "incident.status_changed"
  ],
  "eventTime": 1783000000,
  "workspaceUUID": "wksp_xxx",
  "incident": {
    "uuid": "incident_xxx",
    "name": "API service unavailable",
    "level": "level_1",
    "incidentsStatus": "working",
    "eventRelations": [
      {
        "df_fault_id": "fault_xxx",
        "status": "critical"
      }
    ]
  },
  "isTest": false
}

字段说明:

字段 说明
eventId 一次 Webhook 投递批次的唯一 ID,不是原始事件 ID。
eventTypes 本次批次包含的故障变化类型。
eventTime 本次投递的 Unix 秒级时间戳。
workspaceUUID 故障所属工作空间 UUID。
incident 故障当前完整快照,具体字段见下文。resourceContent 不会推送。
isTest 是否为测试发送。

incident 字段说明

incident 为发送时刻的故障快照。它会随故障的等级、状态、处理人和关联事件变化而更新。

字段 类型 说明
id integer 故障记录的内部数字 ID。
uuid string 故障 UUID,格式为 incident_xxx,建议作为第三方故障主键。
workspaceUUID string 故障所属工作空间 UUID。
name string 故障标题。
level string 当前故障等级 UUID 或等级标识。
description string 故障描述。
incidentsStatus string 故障业务状态。常见值包括 open(待分配)、working(处理中)、resolved(已解决)和 closed(已关闭)。
assigner array 当前处理人账号 UUID 列表;未分配时为空数组。
statusTime object 各故障业务状态对应的时间戳记录。
statusChangeTime integer 最近一次故障业务状态变更的 Unix 秒级时间戳。
cumulativeTime integer 故障累计持续时长,单位为秒。
eventCount integer 当前故障累计关联的事件数量。
eventUpdateAt integer 最近一次关联事件更新的 Unix 秒级时间戳。
eventRelations array 当前关联事件快照,字段说明见下文。
source string 故障来源标识。
resourceCategory string 来源资源分类。
resourceType string 来源资源类型。
resourceUUID string 来源资源 UUID。
resourceUrl string 来源资源的访问地址;无地址时为空。
resourceIdentity string 用于识别同一来源故障的资源标识。
dimensionTag object 故障关联的维度标签。
dtHost string 提取出的主机维度值。
dtService string 提取出的服务维度值。
dtResource string 提取出的资源维度值。
dtPodName string 提取出的 Pod 名称维度值。
dtAppName string 提取出的应用名称维度值。
dtAppId string 提取出的应用 ID 维度值。
dtEnv string 提取出的环境维度值。
dtUrl string 提取出的 URL 维度值。
extend object 故障扩展信息。该对象会随产品能力演进扩展,第三方应忽略不识别的字段。
status integer 故障记录状态,用于标识记录是否有效;不要将其作为故障业务状态使用。
creator string 创建该故障记录的账号 UUID 或系统标识。
updator string 最近更新该故障记录的账号 UUID 或系统标识。
createAt integer 故障记录创建时间,Unix 秒级时间戳。
updateAt integer 故障记录最近更新时间,Unix 秒级时间戳。
deleteAt integer 故障记录删除时间,未删除时通常为负值。

eventRelations 中每一项表示当前关联的一个事件。稳定返回的字段包括:

字段 类型 说明
df_fault_id string 关联事件的故障 ID。
status string 关联事件当前状态,例如 criticalok

不同事件来源可携带额外字段。第三方应按 df_fault_id 识别关联事件,并忽略未识别的扩展字段。聚合故障的关联事件快照发生变化时,会触发"聚合变更"事件。

验证请求来源

第三方接收服务应同时校验 Token、时间戳和签名。

签名原文为:

{timestamp}.{eventId}.{rawRequestBody}

其中 rawRequestBody 是接收到的原始请求字节,不应先格式化或重新序列化 JSON。推荐仅接受当前时间前后 5 分钟内的请求,并按 eventId 去重。

    import hashlib
    import hmac
    import time

    def verify_webhook(request, token):
        raw_body = request.get_data(cache=True)
        timestamp = request.headers.get("X-Incidents-Timestamp", "")
        event_id = request.headers.get("X-Incidents-Event-Id", "")
        signature = request.headers.get("X-Incidents-Signature", "")
        authorization = request.headers.get("Authorization", "")

        if not hmac.compare_digest(authorization, f"Bearer {token}"):
            return False
        if not timestamp.isdigit() or abs(time.time() - int(timestamp)) > 300:
            return False

        message = f"{timestamp}.{event_id}.".encode("utf-8") + raw_body
        expected = "v1=" + hmac.new(
            token.encode("utf-8"), message, hashlib.sha256
        ).hexdigest()
        return hmac.compare_digest(expected, signature)
    import java.nio.charset.StandardCharsets;
    import java.security.MessageDigest;
    import javax.crypto.Mac;
    import javax.crypto.spec.SecretKeySpec;

    boolean verify(byte[] rawBody, String timestamp, String eventId,
                   String signature, String authorization, String token) throws Exception {
        if (!MessageDigest.isEqual(
                authorization.getBytes(StandardCharsets.UTF_8),
                ("Bearer " + token).getBytes(StandardCharsets.UTF_8))) return false;

        byte[] prefix = (timestamp + "." + eventId + ".").getBytes(StandardCharsets.UTF_8);
        byte[] content = new byte[prefix.length + rawBody.length];
        System.arraycopy(prefix, 0, content, 0, prefix.length);
        System.arraycopy(rawBody, 0, content, prefix.length, rawBody.length);

        Mac mac = Mac.getInstance("HmacSHA256");
        mac.init(new SecretKeySpec(token.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
        String expected = "v1=" + java.util.HexFormat.of().formatHex(mac.doFinal(content));
        return MessageDigest.isEqual(expected.getBytes(StandardCharsets.UTF_8),
                                     signature.getBytes(StandardCharsets.UTF_8));
    }
    import (
        "crypto/hmac"
        "crypto/sha256"
        "fmt"
    )

    func verifyWebhook(rawBody []byte, timestamp, eventID, signature, authorization, token string) bool {
        if !hmac.Equal([]byte(authorization), []byte("Bearer "+token)) {
            return false
        }
        content := append([]byte(timestamp+"."+eventID+"."), rawBody...)
        mac := hmac.New(sha256.New, []byte(token))
        mac.Write(content)
        expected := fmt.Sprintf("v1=%x", mac.Sum(nil))
        return hmac.Equal([]byte(expected), []byte(signature))
    }

投递与发送历史

同一个 Webhook 对同一故障在短时间内连续产生多个变化时,系统会合并为一次投递,并在 Payload 的 eventTypes 中返回本次包含的变化类型。Payload 始终以发送时的最新故障快照为准。

系统不自动重试,也不支持手动重试。您可以在发送历史中按发送状态、故障 UUID 或事件类型查看投递结果;失败记录会展示响应码和错误详情,便于排查第三方接收服务。

文档评价

文档内容是否对您有帮助? ×