获取组的增量更改

使用 Microsoft Graph 中的增量查询,可以通过一系列增量请求来查询对受支持资源的添加、删除或更新。 对于组,增量查询使你可以发现更改,而无需提取整组来比较更改。

将组与本地配置文件存储同步的客户端可以使用增量查询进行初始完全同步以及后续增量同步。 通常,客户端对租户中的所有组执行初始完全同步,然后定期获取对组的增量更改。

跟踪对组的更改

使用 增量 函数通过一个或多个 GET 请求跟踪用户更改。 GET 请求具有以下特征:

  • 在 URL 路径前面附加的 delta 函数。
  • 状态令牌 (上一个 GET delta 函数调用中的 deltatokenskiptoken) 。
  • [可选]任何支持的查询参数

示例

本文介绍一系列用于跟踪组更改的示例请求:

  1. 初始请求响应
  2. nextLink 请求响应
  3. 最终的 nextLink 请求响应
  4. deltaLink 请求deltaLink 响应

初始请求

若要跟踪组资源中的更改,请发出请求,并将 增量 函数作为 URL 段。

提示

/delta 是完全限定名称 /microsoft.graph.delta的快捷方式。 Microsoft Graph SDK 生成的请求使用完全限定的名称。

记下以下各项:

  • 请求中包含可选的 $select 查询参数,以演示如何在以后的请求中自动包含查询参数。 如果需要,必须在初始请求中指定查询参数。
    • 仅跟踪 包含的属性 $select 是否发生更改。 如果未 $select 指定 ,则会跟踪对象的所有属性以查找更改。
  • 可选的 $select 查询参数还用于显示如何一起检索组成员和组对象。 此功能允许跟踪成员身份更改,例如在组中添加或删除用户时。
  • 初始请求不包括状态令牌。 状态令牌用于后续请求。
  • 增量函数中查询参数的限制
GET https://graph.microsoft.com/v1.0/groups/delta?$select=displayName,description,members

初始响应

如果成功,此方法在响应正文中返回 200 OK 响应代码和集合对象。 如果整个组集太大,无法容纳在一个响应中, @odata.nextLink 则会包含包含状态令牌的 。

本示例中,返回 @odata.nextLink URL,表示此会话存在要检索的更多数据页面。 $skiptoken请注意 URL 中的 。 初始请求的 $select 查询参数已编码为 @odata.nextLink URL。

属性 members@delta 包含在 “所有公司 ”组中,并包含该组的两个当前成员。 sg-HR 不包含该属性,因为组没有任何成员。

HTTP/1.1 200 OK
Content-type: application/json

{
  "@odata.context":"https://graph.microsoft.com/v1.0/$metadata#groups(displayName,description)",
  "@odata.nextLink":"https://graph.microsoft.com/v1.0/groups/delta?$skiptoken=pqwSUjGYvb3jQpbwVAwEL7yuI3dU1LecfkkfLPtnIjvB7XnF_yllFsCrZJ",
  "value": [
    {
      "displayName":"All Company",
      "description":"This is the default group for everyone in the network",
      "id":"c2f798fd-f95d-4623-8824-63aec21fffff",
      "members@delta": [
               {
                   "@odata.type": "#microsoft.graph.user",
                   "id": "693acd06-2877-4339-8ade-b704261fe7a0"
               },
               {
                   "@odata.type": "#microsoft.graph.user",
                   "id": "49320844-be99-4164-8167-87ff5d047ace"
               }
      ]
    },
    {
      "displayName":"sg-HR",
      "description":"All HR personnel",
      "id":"ec22655c-8eb2-432a-b4ea-8b8a254bffff"
    }
  ]
}

第二个请求使用上一个响应中的 @odata.nextLink,其中包含 skiptoken。 请注意,$select参数在编码并包含在令牌中时并不明显存在。

GET https://graph.microsoft.com/v1.0/groups/delta?$skiptoken=pqwSUjGYvb3jQpbwVAwEL7yuI3dU1LecfkkfLPtnIjvB7XnF_yllFsCrZJ

响应包含另一个@odata.nextLink,其中有一个新的skiptoken值,这表示为组跟踪的更多更改可用。 @odata.nextLink在后续请求中使用 URL,直到@odata.deltaLink在最终响应中@odata.deltaLink返回参数 (URL) ,即使值为空数组也是如此。

HTTP/1.1 200 OK
Content-type: application/json

{
  "@odata.context":"https://graph.microsoft.com/v1.0/$metadata#groups",
  "@odata.nextLink":"https://graph.microsoft.com/v1.0/groups/delta?$skiptoken=pqwSUjGYvb3jQpbwVAwEL7yuI3dU1LecfkkfLPtnIjtQ5LOhVoS7qQG_wdVCHHlbQpga7",
  "value": [
    {
      "displayName":"Mark 8 Project Team",
      "description":"Mark 8 Project Team",
      "id":"2e5807ce-58f3-4a94-9b37-ffff2e085957",
      "members@delta": [
               {
                   "@odata.type": "#microsoft.graph.user",
                   "id": "632f6bb2-3ec8-4c1f-9073-0027a8c68593"
               }
      ]
    },
    {
      "displayName":"Sales and Marketing",
      "description":"Sales and Marketing",
      "id":"421e797f-9406-4934-b778-4908421e3505",
      "members@delta": [
               {
                   "@odata.type": "#microsoft.graph.user",
                   "id": "3c8ac7c4-d365-4df9-abfa-356a9dd7763c"
               },
               {
                   "@odata.type": "#microsoft.graph.user",
                   "id": "49320844-be99-4164-8167-87ff5d047ace"
               }
      ]
    }
  ]
}

第三个请求使用上次同步请求返回的最新 @odata.nextLink

GET https://graph.microsoft.com/v1.0/groups/delta?$skiptoken=ppqwSUjGYvb3jQpbwVAwEL7yuI3dU1LecfkkfLPtnIjtQ5LOhVoS7qQG_wdVCHHlbQpga7

返回 @odata.deltaLink URL 时,不再有有关组对象的现有状态的数据。 对于将来的请求,应用程序使用 @odata.deltaLink URL 了解组的其他更改。 保存 deltatoken并在后续请求 URL 中使用它来发现对组的更多更改。

HTTP/1.1 200 OK
Content-type: application/json

{
  "@odata.context":"https://graph.microsoft.com/v1.0/$metadata#groups",
  "@odata.deltaLink":"https://graph.microsoft.com/v1.0/groups/delta?$deltatoken=sZwAFZibx-LQOdZIo1hHhmmDhHzCY0Hs6snoIHJCSIfCHdqKdWNZ2VX3kErpyna9GygROwBk-rqWWMFxJC3pw",
  "value": [
    {
      "displayName":"All Employees",
      "id":"bed7f0d4-750e-4e7e-ffff-169002d06fc9"
    },
    {
      "displayName":"Remote living",
      "description":"Remote living",
      "id":"421e797f-9406-ffff-b778-4908421e3505"
    }
  ]
}

@odata.deltaLink使用上次响应中的 ,可获取自上次请求以来对组 (添加、删除或更新) 的更改。 这些更改包括:

  • 新创建的组对象。
  • 已删除的组对象。
  • 对跟踪属性更改的对象进行分组 (例如,更新的 displayName) 。
  • 为其添加或删除成员对象的组对象。
GET https://graph.microsoft.com/v1.0/groups/delta?$deltatoken=sZwAFZibx-LQOdZIo1hHhmmDhHzCY0Hs6snoIHJCSIfCHdqKdWNZ2VX3kErpyna9GygROwBk-rqWWMFxJC3pw

如果没有更改, @odata.deltaLink 则返回 不带结果的 - value 属性为空数组。 请确保将应用程序中的以前链接替换为新链接以便在日后调用中使用。

HTTP/1.1 200 OK
Content-type: application/json

{
  "@odata.context":"https://graph.microsoft.com/v1.0/$metadata#groups",
  "@odata.deltaLink":"https://graph.microsoft.com/v1.0/groups/delta?$deltatoken=sZwAFZibx-LQOdZIo1hHhmmDhHzCY0Hs6snoIHJCSIfCHdqKdWNZ2VX3kErpyna9GygROwBk-rqWWMFxJC3pw",
  "value": []
}

如果有更改,则包含已更改组的集合。 响应还包含 @odata.nextLink@odata.deltaLink(如果要检索多个更改页面)。 实现遵循 @odata.nextLink 的相同模式,并为将来的调用保留最终 @odata.deltaLink

注意

此请求可能对最近创建、更新或删除的组具有复制延迟。 请在一段时间后重试 @odata.nextLink@odata.deltaLink 以检索最新更改。

有关示例响应的一些注意事项:

  • 这些对象连同一组相同的属性一起返回,这些属性最初通过 $select 查询参数指定。
  • 包括已更改的属性和未更改的属性 - description 属性具有新值,而 displayName 属性未更改。
  • members@delta包含对组成员身份的以下更改。
    • 已通过删除其成员身份从组中删除了 ID 632f6bb2-3ec8-4c1f-9073-0027a8c6859 的用户,如 属性所述 @removed 。 增量查询不会检测到通过删除对象从组中删除的对象。
    • 具有 ID 37de1ae3-408f-4702-8636-20824abda004 的第二个用户已添加到组。

在以下方案中, @removed 组对象可以包含批注:

  • 删除组(Microsoft 365组)时,项包含批注: @removed 值为 "reason": "changed"
  • 当 (安全组永久删除组或 永久删除Microsoft 365 组) 时,该项包含一个注释: @removed 值为 "reason": "deleted"
  • 创建或还原组时,没有批注。
HTTP/1.1 200 OK
Content-type: application/json

{
  "@odata.context":"https://graph.microsoft.com/v1.0/$metadata#groups",
  "@odata.deltaLink":"https://graph.microsoft.com/v1.0/groups/delta?$deltatoken=sZwAFZibx-LQOdZIo1hHhmmDhHzCY0Hs6snoIHJCSIfCHdqKdWNZ2VX3kErpyna9GygROwBk-rqWWMFxJC3pw",
  "value": [
          {
              "displayName": "TestGroup3",
              "description": "A test group for change tracking",
              "id": "2e5807ce-58f3-4a94-9b37-ffff2e085957",
              "members@delta": [
                  {
                      "@odata.type": "#microsoft.graph.user",
                      "id": "632f6bb2-3ec8-4c1f-9073-0027a8c6859",
                      "@removed": {
                          "reason": "deleted"
                      }
                  },
                  {
                      "@odata.type": "#microsoft.graph.user",
                      "id": "37de1ae3-408f-4702-8636-20824abda004"
                  }
              ]
          }
      ]
}

逐页查看大型组中的成员

members@delta默认情况下,如果未指定查询参数或$select$select=members显式指定参数,则属性包含在组对象中。 对于具有多个成员的组,可能所有成员都无法适应单个响应。 实现以下模式来处理此类情况。

注意

此模式既适用于组状态的初始检索,也适用于获取增量更改的后续调用。

假设运行以下增量查询 - 捕获组的初始完整状态,或稍后获取增量更改:

GET https://graph.microsoft.com/v1.0/groups/delta?$select=displayName,description,members
  1. Microsoft Graph 可能会返回仅包含一个组对象的响应,并在 属性中包含 members@delta 大量成员列表:

第一页

HTTP/1.1 200 OK
Content-type: application/json

{
  "@odata.context":"https://graph.microsoft.com/v1.0/$metadata#groups",
  "@odata.nextLink":"https://graph.microsoft.com/v1.0/groups/delta?$skiptoken=<...>",
  "value": [
    {
      "displayName":"LargeGroup",
      "description":"A group containing thousands of users",
      "id":"2e5807ce-58f3-4a94-9b37-ffff2e085957",
      "members@delta": [
          {
              "@odata.type": "#microsoft.graph.user",
              "id": "632f6bb2-3ec8-4c1f-9073-0027a8c6859",
              "@removed": {
                  "reason": "deleted"
              }
          },
          {
              "@odata.type": "#microsoft.graph.user",
              "id": "37de1ae3-408f-4702-8636-20824abda004"
          },
          <...more users here...>
      ]
    }
    <...no more groups included - this group filled out the entire response...>
  ]
}
  1. 遵循 时, @odata.nextLink可能会收到包含同一组对象的响应。 返回相同的属性值,但该 members@delta 属性现在包含不同的用户列表。

第二页

HTTP/1.1 200 OK
Content-type: application/json
{
  "@odata.context":"https://graph.microsoft.com/v1.0/$metadata#groups",
  "@odata.nextLink":"https://graph.microsoft.com/v1.0/groups/delta?$skiptoken=<...>",
  "value": [
    {
      "displayName":"LargeGroup",
      "description":"A group containing thousands of users",
      "id":"2e5807ce-58f3-4a94-9b37-ffff2e085957",
      "members@delta": [
          {
              "@odata.type": "#microsoft.graph.user",
              "id": "c08a463b-7b8a-40a4-aa31-f9bf690b9551",
              "@removed": {
                  "reason": "deleted"
              }
          },
          {
              "@odata.type": "#microsoft.graph.user",
              "id": "23423fa6-821e-44b2-aae4-d039d33884c2"
          },
          <...more users here...>
      ]
    }
    <...no more groups included - this group filled out the entire response...>
  ]
}
  1. 最终,以这种方式返回整个成员列表,其他组开始显示在响应中。

建议使用以下最佳做法来正确处理此模式:

  • 始终按照 @odata.nextLink 操作,并在本地合并每个组的状态:当收到与同一个组相关的响应时,使用它们在应用程序中构建完整的成员身份列表。
  • 不要假定特定的响应序列。 假设同一组可以显示在 @odata.nextLink 序列的任意位置,并以合并逻辑进行处理。