通过 Webhook 接收更改通知

Webhook 是基于 HTTP 的用户定义回调 API,可在基础结构中进行设置,以接收来自服务(如 Microsoft Graph)的更改通知和事件。 若要使用 Webhook,需要定义一个可公开访问的 HTTPS 保护终结点,该终结点将接收通知。

可以创建要收到更改通知的资源的订阅。 当订阅有效时,Microsoft Graph 会在检测到资源更改时向终结点发送通知。

本文指导你完成实现 Webhook 终结点、订阅和管理 Microsoft Graph 订阅以及如何通过 Webhook 接收更改通知的过程。

有关如何创建更改通知的详细信息,请参阅 Microsoft Graph API 更改通知

Webhook 终结点的注意事项

在通过 Webhook 接收通知之前,必须创建一个可公开访问的 HTTPS 保护终结点,该终结点可通过 URL 进行寻址。 如果终结点不可公开访问,Microsoft Graph 不会向终结点发送通知。

终结点必须提供正确、一致且及时的 HTTP 响应,才能可靠地接收通知。 如果终结点未及时响应,更改通知服务可能会开始删除通知。 无法恢复已删除的通知。

终结点还必须通过持续续订订阅或响应生命周期通知,继续向 Microsoft Graph 进行身份验证。

HTTP 代码和重试逻辑

Microsoft Graph 更改通知服务从终结点收到 2xx 类代码后,该通知被视为已发送。 只要更改通知服务在 3 秒内收到任何其他 HTML 响应 (甚至错误代码) ,该服务就将继续尝试传递通知长达 4 小时。

  • 如果能够在 3 秒的窗口中处理通知,则应将状态代码返回到 200 - OK Microsoft Graph
  • 如果服务可能需要 3 秒以上的时间来处理通知,则可以选择将通知保留在终结点上的队列中,并将状态代码返回 202 - Accepted 给 Microsoft Graph。
  • 如果通知未处理或未排队,请返回 5xx 类代码以指示错误,以便 Microsoft Graph 可以重试通知。

无法传递的通知将按指数回退间隔重试。 终结点联机后,错过的通知最多可能需要 4 小时才能重新发送。

限制

出于安全和性能原因,Microsoft Graph 会限制发送到变得缓慢或无响应的终结点的通知。 这可能包括以无法恢复的方式删除通知。

  1. 终结点在 10 分钟窗口中标记为“慢”一次超过 10% 的响应需要 3 秒以上。

    • 将终结点标记为“慢”后,将在 10 秒延迟的情况下发送任何新通知。
    • 终结点在 10 分钟的时段内退出“慢速”状态,不到 10% 的响应花费的时间超过 3 秒。
  2. 终结点在 10 分钟的时段内被标记为“删除”超过 15% 的响应需要 3 秒以上。

    • 终结点标记为“删除”后,将删除任何新通知,最长 10 分钟
    • 终结点在 10 分钟的时段内退出“删除”状态的时间超过 15% 的响应时间超过 3 秒。

如果终结点无法满足这些性能特征,请考虑使用 事件中心事件网格 作为接收通知的目标。

身份验证

创建订阅时,会向终结点发送访问令牌。 此访问令牌仅用于检查终结点的有效性,其生命周期与更改通知订阅不同。 此访问令牌通常在 1 小时内过期。

终结点必须准备好定期使用 Microsoft Graph 重新授权,以确保 Microsoft Graph 可以继续向终结点发送通知。

如果访问令牌过期,将不会传递通知。 但是,这不会触发终结点限制行为,Microsoft Graph 将继续重试发送每个通知长达 4 小时。 因此,如果在过期后的 4 小时内刷新访问令牌,则会传递未发送的通知。

建议将 生命周期通知 添加到订阅,以接收有关令牌过期的警告,以便可以及时重新授权终结点。

续订订阅时,访问令牌也会刷新。

防火墙配置

可以将保护终结点的防火墙配置为仅允许来自 Microsoft Graph 的入站连接,从而减少对无效更改通知的进一步风险。 有关 Microsoft Graph 用于传递更改通知的 IP 地址的完整列表,请参阅 Microsoft 365 的其他终结点

注意

用于传递更改通知的已列出 IP 地址可能随时更新,恕不另行通知。

创建订阅

重要

需要执行多个步骤来确保在 Microsoft Graph 更改通知服务和终结点之间建立和维护安全信道。

若要开始接收 Microsoft Graph 更改通知,必须使用终结点的 URL (通知 URL) 创建订阅以建立订阅。 建立订阅的模式如下所示:

  1. 客户端应用发送订阅请求来订阅特定资源上的更改。

  2. Microsoft Graph 检查请求。

    • 如果请求有效,Microsoft Graph 会将验证令牌发送到客户端应用的通知 URL,以验证通知 URL。
    • 如果请求无效,Microsoft Graph 会发送包含错误代码和详细信息的错误响应。
  3. 当客户端收到通知 URL 验证请求时,客户端会以纯文本形式响应验证令牌。

  4. Microsoft Graph 验证客户端的验证令牌响应,如果验证令牌有效,则使用订阅 ID 进行响应。

订阅请求

客户端应用向终结点发送 POST 请求 /subscriptions 。 以下示例演示代表已登录用户订阅对特定邮件文件夹的更改的基本请求。 有关支持更改通知的其他 Microsoft Graph 资源的详细信息,请参阅 支持的资源

POST https://graph.microsoft.com/v1.0/subscriptions
Content-Type: application/json

{
  "changeType": "created,updated",
  "notificationUrl": "https://webhook.azurewebsites.net/notificationClient",
  "lifecycleNotificationUrl": "https://webhook.azurewebsites.net/api/lifecycleNotifications",
  "resource": "/me/mailfolders('inbox')/messages",
  "expirationDateTime": "2016-03-20T11:00:00.0000000Z",
  "clientState": "SecretClientState"
}

clientState 属性是必需的。 设置此属性可让你的服务确认你收到的更改通知是否源自 Microsoft Graph。 因此,该属性的值应保密,并且只有你的应用程序和 Microsoft Graph 服务知道。

如果成功,Microsoft Graph 将在正文中返回 201 Created 代码和 subscription 对象。

每个订阅都有一个唯一的 subscriptionId,即使有多个订阅监视同一资源并使用相同的通知 URL。

注意

当通知传递到服务时, notificationUrl 属性中包含的任何查询字符串参数都包含在 HTTP POST 请求中。

不允许重复订阅。 当订阅请求包含与现有订阅相同的 changeType和资源值 时,请求失败并显示 HTTP 错误代码 409 Conflict和错误消息 Subscription Id <> already exists for the requested combination

notificationUrl 验证

发送创建订阅以通过 Webhook 获取更改通知的请求时,订阅服务会检查订阅请求中的 notificationUrl 属性是否有效。 验证过程的工作方式如下:

注意

如果还要订阅 生命周期通知 ,订阅服务还会验证 lifecycleNotificationUrl

  1. 请求订阅时,Microsoft Graph 会对验证令牌进行编码,并将其包含在通知 URL 的 POST 请求中,如下所示。

    Content-Type: text/plain; charset=utf-8
    POST https://{notificationUrl}?validationToken={opaqueTokenCreatedByMicrosoftGraph}
    
  2. 客户端必须正确解码 URL 才能从 Microsoft Graph 获取纯文本验证令牌。

    转义任何 HTML 或 JavaScript 是一种很好的做法,因为恶意参与者可以使用通知终结点进行跨站点脚本类型的攻击。 Microsoft Graph 从不发送任何包含 HTML 或 JavaScript 代码的值。

    通常,将验证令牌值视为不透明,因为令牌格式可能会更改,无需通知。

  3. 客户端必须在步骤 1 的 10 秒内响应以下特征:

    • HTTP 200 OK 状态代码。
    • text/plain 的内容类型。
    • 包含 URL 解码的 纯文本验证令牌的正文。

    重要

    必须以纯文本形式返回验证令牌。 如果客户端返回已编码的验证令牌,则验证将失败。

  4. 如果终结点验证失败,Microsoft Graph 不会创建订阅。

接收通知

当订阅有效且已订阅的资源发生更改时,Microsoft Graph 会向 notificationUrl 发送一个POST请求,其中包含更改的详细信息。 此有效负载是 更改通知

对于大多数订阅,Microsoft Graph 不会延迟发送通知,而是 在 SLA 中传递所有通知,除非服务遇到事件

发送到终结点的更改通知有效负载可以包含与订阅相关的更改通知集合。

更改通知示例

当用户收到电子邮件时,Microsoft Graph 会向客户端应用发送更改通知对象,如以下示例所示。 有关通知有效负载的详细信息,请参阅 changeNotificationCollection 和相关 changeNotification

发生许多更改时,Microsoft Graph 可能会在同一 POST 请求中发送对应于不同订阅的多个通知。

{
  "value": [
    {
      "id": "lsgTZMr9KwAAA",
      "subscriptionId":"{subscription_guid}",
      "subscriptionExpirationDateTime":"2016-03-19T22:11:09.952Z",
      "clientState":"secretClientValue",
      "changeType":"created",
      "resource":"users/{user_guid}@{tenant_guid}/messages/{long_id_string}",
      "tenantId": "84bd8158-6d4d-4958-8b9f-9d6445542f95",
      "resourceData":
      {
        "@odata.type":"#Microsoft.Graph.Message",
        "@odata.id":"Users/{user_guid}@{tenant_guid}/Messages/{long_id_string}",
        "@odata.etag":"W/\"CQAAABYAAADkrWGo7bouTKlsgTZMr9KwAAAUWRHf\"",
        "id":"{long_id_string}"
      }
    }
  ]
}

处理更改通知

收到更改通知时:

  1. 验证 clientState 属性。 它必须与最初使用订阅创建请求提交的值匹配。

    如果不匹配,请勿将更改通知视为有效。 更改通知可能不是来自 Microsoft Graph,并且可能是由流氓参与者发送的。 还应调查更改通知来自何处并采取适当的措施。

  2. 根据业务逻辑更新客户端应用。

订阅生命周期

当不再需要订阅时,订阅可能会被删除或过期。 创建订阅时,使用 expirationDateTime 属性设置到期日期。 此时间过后,Microsoft Graph 会删除订阅,并且不会向终结点发送通知。 还可以显式删除订阅。

继续接收通知的最简单方法是继续续订订阅请求。 每个通知都包含 一个 subscriptionExpirationDateTime 属性。 可以使用此来指导何时续订订阅。

每个订阅还包括授予终结点的访问令牌。 此访问令牌的过期时间可能在订阅过期之前发生。 可以使用订阅的生命周期通知来管理访问令牌过期。

续订订阅

PATCH https://graph.microsoft.com/v1.0/subscriptions/{id}
Content-Type: application/json

{
  "expirationDateTime": "2016-03-22T11:00:00.0000000Z"
}

如果订阅续订请求成功,Microsoft Graph 将在 200 OK 响应正文中返回响应代码和 订阅 对象。 订阅对象包括新的 expirationDateTime 值。

删除订阅

如果客户端应用不再需要更改通知,可以使用其 subscriptionId 删除订阅,如下所示:

DELETE https://graph.microsoft.com/v1.0/subscriptions/{id}

如果成功,Microsoft Graph 将返回 204 No Content 代码。

订阅的生命周期通知

为了提高灵活性和可靠性,在创建订阅时,还可以通过提供 一个 lifecycleNotificationUrl 终结点来订阅该订阅的生命周期通知,该终结点将接收、处理和响应生命周期通知。

订阅生命周期通知时,Microsoft Graph 会发出以下警报:

  • 访问令牌即将过期时。
  • 订阅即将过期时。
  • 当租户管理员撤销了应用读取资源的权限时。

注意

如果访问令牌过期,则不会在终结点上传递通知。 但 Microsoft Graph 将继续重试发送每个通知长达 4 小时。 因此,如果在过期后的 4 小时内刷新访问令牌,则会传递未发送的通知。

有关如何为订阅使用生命周期通知的详细信息,请参阅 生命周期通知

摘要

本文介绍了如何通过 Webhook 接收更改通知。

  1. 通过向终结点发送 POST 请求 /subscriptions 来创建订阅。
  2. Microsoft Graph 将在完成订阅创建过程之前验证 Webhook 通知终结点。 唯一 的 subscriptionId 链接到订阅。
  3. 只要订阅仍然有效,并且订阅的资源发生更改,Microsoft Graph 就会向 notificationUrl 终结点发送更改通知。
  4. 定期续订订阅以保持其有效性,并继续接收有关订阅更改的更新。