批处理 | Graph API 概念

使用 Azure AD Graph API 时,你可以通过对实体上的操作执行批处理来减少往返服务器的操作。 对请求进行批处理可减少网络开销,使你的操作更快地完成。

重要

强烈建议使用 Microsoft Graph 代替 Azure AD Graph API 来访问 Azure Active Directory 资源。现在我们的开发工作将重点集中在 Microsoft Graph 上,没有计划对 Azure AD Graph API 进行进一步的改进。Azure AD Graph API 仍适用的方案数量非常有限;有关详细信息,请参阅 Office 开发人员中心中的博客文章 Microsoft Graph 或 Azure AD Graph

Graph API 支持 OData 批处理请求

实体批处理操作的语义由 OData 3.0 批处理规范定义。 OData 规范定义以下批处理请求的概念:

  • 一个查询是单个的查询或函数调用。
  • “更改集”是由一个或多个插入、更新或删除操作、操作调用或服务调用组成的组。
  • “批处理”是操作容器,包含一个或多个更改集和查询操作。

Graph API 支持 OData 规范所定义的功能子集:

  • 单个批处理最多可以包含五个组合性的查询和/或更改集。
  • 一个更改集最多只能包含一个组合性的源对象修改和最多 20 项添加链接和删除链接操作。 在更改集中的所有操作必须针对单个源实体。

Graph API 批处理请求

下面几节介绍如何构造批处理请求以及如何解释批处理响应,并给出相应示例。

批处理请求语法

若要执行批处理请求,请对请求 URI 指定 $batch 选项。 例如:

https://graph.windows.net/contoso.onmicrosoft.com/$batch?api-version=1.6

批处理请求通过一条 POST 指令发送给服务器。

负载是由多个部分组成的 MIME 消息,其中包含批处理及其构成性查询和更改集。 负载包含两类 MIME 边界:

  • 批处理边界用于分隔批处理中的每个查询和/或更改集。
  • 更改集边界用于将更改集内的各个操作分隔开。

更改集中的单个请求与操作被自身调用时发出的请求相同。 例如:

  • 若要指定更改集中每个操作的负载格式(JSON 或 ATOM),可包括相应的 Content-Type 并根据需要包括 Accept 标头。
  • 若要在创建实体时抑制响应内容回显,请对更改集中的每个插入操作指定具有 return-no-content 值的 Prefer 标头。

示例请求

下面的示例演示包含以下五项的批处理请求:

  1. 一个更改集,用于创建用户 testuser@contoso.onmicrosoft.com (POST)。 此操作包括 Prefer: response-no-content 标头,用于抑制所返回的新创建的用户。
  2. 一个更改集,用于更新新用户的“Department(部门)”和“Job Title(职务)”属性 (PATCH),并设置其 manager(经理)导航属性 (PUT)。
  3. 针对新用户的经理的查询 (GET)。
  4. 一个更改集,用于删除新用户 (DELETE)。
  5. 一个针对用户的查询 (GET)。 此操作将失败,因为用户在上一步中已被删除。
POST https://graph.windows.net/contoso.onmicrosoft.com/$batch?api-version=1.5 HTTP/1.1
Authorization: Bearer ey … jQA
Content-Type: multipart/mixed; boundary=batch_36522ad7-fc75-4b56-8c71-56071383e77b 
Host: graph.windows.net
Content-Length: 2961

--batch_36522ad7-fc75-4b56-8c71-56071383e77b 
Content-Type: multipart/mixed; boundary=changeset_77162fcd-b8da-41ac-a9f8-9357efbbd620 
Content-Length: 631       

--changeset_77162fcd-b8da-41ac-a9f8-9357efbbd620 
Content-Type: application/http 
Content-Transfer-Encoding: binary 

POST /contoso.onmicrosoft.com/users?api-version=1.5 HTTP/1.1
Content-Type: application/json
Accept: application/json
Content-Length: 256
Prefer: return-no-content
Host: graph.windows.net

{
    "accountEnabled": true,
    "displayName": "Test User",
    "mailNickname": "testuser",
    "passwordProfile": { "password" : "Test1234", "forceChangePasswordNextLogin": false },
    "userPrincipalName": "testuser@contoso.onmicrosoft.com"
}

--changeset_77162fcd-b8da-41ac-a9f8-9357efbbd620----batch_36522ad7-fc75-4b56-8c71-56071383e77b 
Content-Type: multipart/mixed; boundary=changeset_4b2cbfb7-011d-4edb-8bbf-e044f9830aaf 
Content-Length: 909

--changeset_4b2cbfb7-011d-4edb-8bbf-e044f9830aaf 
Content-Type: application/http 
Content-Transfer-Encoding: binary 

PATCH /contoso.onmicrosoft.com/users/testuser@contoso.onmicrosoft.com?api-version=1.5 HTTP/1.1
Content-Type: application/json
Accept: application/json
Content-Length: 72
Host: graph.windows.net

{
    "department": "Engineering",
    "jobTitle": "Test Engineer"
}

--changeset_4b2cbfb7-011d-4edb-8bbf-e044f9830aaf 
Content-Type: application/http 
Content-Transfer-Encoding: binary 

PUT /contoso.onmicrosoft.com/users/testuser@contoso.onmicrosoft.com/$links/manager?api-version=1.5 HTTP/1.1
Content-Type: application/json
Accept: application/json
Content-Length: 112
Host: graph.windows.net

{
  "url":"https://graph.windows.net/contoso.onmicrosoft.com/users/a71e4d1c-ce99-40dc-8d4b-390eac63e039"
}

--changeset_4b2cbfb7-011d-4edb-8bbf-e044f9830aaf----batch_36522ad7-fc75-4b56-8c71-56071383e77b 
Content-Type: application/http 
Content-Transfer-Encoding:binary

GET /contoso.onmicrosoft.com/users/testuser@contoso.onmicrosoft.com/$links/manager?api-version=1.5 HTTP/1.1
Accept: application/json
Host: graph.windows.net

--batch_36522ad7-fc75-4b56-8c71-56071383e77b 
Content-Type: multipart/mixed; boundary=changeset_9a0b5878-0f4a-4f57-91c5-9792cdd5ef20 
Content-Length: 331       

--changeset_9a0b5878-0f4a-4f57-91c5-9792cdd5ef20 
Content-Type: application/http 
Content-Transfer-Encoding: binary 

DELETE /contoso.onmicrosoft.com/users/testuser@contoso.onmicrosoft.com?api-version=1.5 HTTP/1.1
Accept: application/json
Host: graph.windows.net


--changeset_9a0b5878-0f4a-4f57-91c5-9792cdd5ef20----batch_36522ad7-fc75-4b56-8c71-56071383e77b 
Content-Type: application/http 
Content-Transfer-Encoding:binary

GET /contoso.onmicrosoft.com/users/testuser@contoso.onmicrosoft.com?api-version=1.5 HTTP/1.1
Accept: application/json
Host: graph.windows.net

--batch_36522ad7-fc75-4b56-8c71-56071383e77b--

批处理响应语法

响应返回批处理请求的总体状态代码以及批处理中每个项的各状态代码和结果片段。 响应是由多个部分组成的 MIME 消息,其中包含批边界和更改集边界。

假设批处理请求正确经过身份验证并已成功由 Graph API 接收,即使批处理中的某项操作失败,批处理请求也会返回状态代码 202 已接受。 如果批处理请求本身失败,在批处理中的任何操作执行之前就会失败。 例如,批处理请求可能由于身份验证错误失败,在这种情况下,状态代码将指示失败。

查询项的响应段中包含指示操作成功或失败的单个状态代码,以及任何适当的响应正文。

更改集中的操作以原子方式处理;即,要么更改集中的所有操作都成功,要么整个更改集失败。 Graph API 继续处理更改集中的操作,直到一项操作失败。 如果某一操作失败,则更改集中前面的所有操作都将回滚。

如果更改集中的所有操作都成功进行了处理,则更改集中每项操作的状态代码(以及响应正文)都将显示在更改集响应中。 如果更改集中的某项操作失败,则只为更改集返回单个状态代码。 这将是由失败的操作返回的状态代码(以及响应正文);例如,400 错误的请求404 未找到

示例响应

下面的示例介绍上面所示的示例请求中发送的批处理操作的响应。 批处理请求本身的状态设置为 202 已接受。 这表示批处理请求本身没有问题。 批处理中每一项的响应使用 batchresponse 边界标识符进行分隔,更改集中操作的每项响应均使用 changesetresponse 边界标识符进行分隔。

下面列出了每个批处理项的响应片段:

  1. 用于创建新用户的 POST 请求的状态设置为 204 无内容。 这是因为请求中的 Prefer 标头已设置为 return-no-content。 它表示已成功创建用户。
  2. 第二个批处理项的响应包含两个 204 无内容* 响应,一个用于用户对象更新 (PATCH),另一个用于设置更改集中的经理链接 (PUT)。 这表明两个操作都已成功完成。
  3. 用于读取用户经理的请求的响应,返回该经理的链接和状态 200 正常
  4. 尝试删除用户时,状态为 204 无内容。 这表明该操作已成功
  5. 尝试读取已删除的用户时,状态为 404 未找到,而响应则包含代码和消息,消息指示尚未找到用户(资源)。
HTTP/1.1 202 Accepted
Cache-Control: no-cache
Pragma: no-cache
Content-Type: multipart/mixed; boundary=batchresponse_1eb70252-25d2-466c-9a1d-7a3f45378b06
Expires: -1
Server: Microsoft-IIS/8.5
ocp-aad-diagnostics-server-name: Nv0YIi2YUldDWu0YPQAXsYwXQ4ttyr7ded6Waf8xyCc=
request-id: 2f7d2f81-3441-4c2a-b494-25cd1d6ce624
client-request-id: f40c00af-3e1f-4198-9261-386f0e3aecc6
x-ms-gateway-rewrite: false
x-ms-dirapi-data-contract-version: 1.5
ocp-aad-session-key: cdhenl3mgHuI3vaRRIQ14uXdwRLUqirNpDXjJP42EzUEvqhhn2NFr22ulR4PsqrM1UD_eSUDItt7J9kUQhNvTT_48q90coHHt2RutCIgPNg.lD81Z0iS2SaHbqkfAaDvbbigoX7ak7rfiUGFby0LOIE
X-Content-Type-Options: nosniff
DataServiceVersion: 1.0;
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
X-Powered-By: ASP.NET
Date: Tue, 20 Jan 2015 23:21:15 GMT
Content-Length: 3065

--batchresponse_1eb70252-25d2-466c-9a1d-7a3f45378b06
Content-Type: multipart/mixed; boundary=changesetresponse_8a63ce5e-ed31-4de6-bc90-9d3ff31debbb--changesetresponse_8a63ce5e-ed31-4de6-bc90-9d3ff31debbb
Content-Type: application/http
Content-Transfer-Encoding: binary

HTTP/1.1 204 No Content
X-Content-Type-Options: nosniff
Cache-Control: no-cache
Preference-Applied: return-no-content
DataServiceVersion: 3.0;
Location: https://graph.windows.net/contoso.onmicrosoft.com/directoryObjects/6a287a96-ede9-44d2-b685-d6fc03a124c5/Microsoft.DirectoryServices.User
DataServiceId: https://graph.windows.net/contoso.onmicrosoft.com/directoryObjects/6a287a96-ede9-44d2-b685-d6fc03a124c5


--changesetresponse_8a63ce5e-ed31-4de6-bc90-9d3ff31debbb----batchresponse_1eb70252-25d2-466c-9a1d-7a3f45378b06
Content-Type: multipart/mixed; boundary=changesetresponse_11ba5cf0-9fba-4995-9f15-bd5c9981cdd6--changesetresponse_11ba5cf0-9fba-4995-9f15-bd5c9981cdd6
Content-Type: application/http
Content-Transfer-Encoding: binary

HTTP/1.1 204 No Content
X-Content-Type-Options: nosniff
Cache-Control: no-cache
DataServiceVersion: 1.0;


--changesetresponse_11ba5cf0-9fba-4995-9f15-bd5c9981cdd6
Content-Type: application/http
Content-Transfer-Encoding: binary

HTTP/1.1 204 No Content
X-Content-Type-Options: nosniff
Cache-Control: no-cache
DataServiceVersion: 1.0;


--changesetresponse_11ba5cf0-9fba-4995-9f15-bd5c9981cdd6----batchresponse_1eb70252-25d2-466c-9a1d-7a3f45378b06
Content-Type: application/http
Content-Transfer-Encoding: binary

HTTP/1.1 200 OK
DataServiceVersion: 3.0;
Content-Type: application/json;odata=minimalmetadata;streaming=true;charset=utf-8
X-Content-Type-Options: nosniff
Cache-Control: no-cache

{
  "odata.metadata":"https://graph.windows.net/contoso.onmicrosoft.com/$metadata#directoryObjects/$links/manager",
  "url":"https://graph.windows.net/contoso.onmicrosoft.com/directoryObjects/a71e4d1c-ce99-40dc-8d4b-390eac63e039/Microsoft.DirectoryServices.User"
}
--batchresponse_1eb70252-25d2-466c-9a1d-7a3f45378b06
Content-Type: multipart/mixed; boundary=changesetresponse_bb215a84-f91e-4486-a771-ba2cc5d429d1--changesetresponse_bb215a84-f91e-4486-a771-ba2cc5d429d1
Content-Type: application/http
Content-Transfer-Encoding: binary

HTTP/1.1 204 No Content
X-Content-Type-Options: nosniff
Cache-Control: no-cache
DataServiceVersion: 1.0;


--changesetresponse_bb215a84-f91e-4486-a771-ba2cc5d429d1----batchresponse_1eb70252-25d2-466c-9a1d-7a3f45378b06
Content-Type: application/http
Content-Transfer-Encoding: binary

HTTP/1.1 404 Not Found
X-Content-Type-Options: nosniff
Cache-Control: no-cache
DataServiceVersion: 3.0;
Content-Type: application/json;odata=minimalmetadata;streaming=true;charset=utf-8

{
  "odata.error":
    {
      "code":"Request_ResourceNotFound",
      "message":
        {
          "lang":"en",
          "value":"Resource 'testuser@contoso.onmicrosoft.com' does not exist or one of its queried reference-property objects are not present."
        }
    }
}
--batchresponse_1eb70252-25d2-466c-9a1d-7a3f45378b06--

示例错误响应

如上文所述,Graph API 为整个批处理返回的错误代码为 202 已接受,前提是它能够接受该批处理;也就是说,如果批处理请求的格式正确且没有错误(例如身份验证错误)。 否则,Graph API 会返回相应的错误,并且不会处理该批次。 如果批处理中的单个项失败,则该项的响应片段将包含指示该错误的状态代码和响应正文。 当更改集中的操作失败时,将为整个更改集返回单个响应片段,该片段将包含与失败的操作关联的状态代码和响应正文。

下面的示例显示了来自批处理请求的响应,某个操作在该请求所包含的更改集中失败。 请注意,批处理响应返回状态代码 202 已接受。 为更改集返回的状态代码指示某个操作失败,状态为 404 未找到。 响应正文包含失败操作的更多错误信息。 代码元素指定 Graph API 错误代码,消息 元素包含错误消息字符串。 在此示例中,响应正文已被缩进以提高可读性。

HTTP/1.1 202 Accepted
Cache-Control: no-cache
Pragma: no-cache
Content-Type: multipart/mixed; boundary=batchresponse_3ac28387-a100-4758-8998-8b9ec36f9fdc
Expires: -1
Server: Microsoft-IIS/8.5
ocp-aad-diagnostics-server-name: 1l3fvSoDCV+VKoBCuHRN+HIwCACBOck3dqmtCGj+aiU=
request-id: e434261b-c32f-48b4-b21d-3e1beab6d525
client-request-id: 236bf26e-b4e8-40a4-b6fb-d41105a7b178
x-ms-gateway-rewrite: false
x-ms-dirapi-data-contract-version: 1.5
ocp-aad-session-key: 9aOaAUxX95OZ0ctrYbeLUproN-37GypZXrss0PYKhEfqamKRG-C68hFcCw5h-ZCWFqBrXPrldGEnjq4CKKr0bW91tjrdo-BlwAqHxbP5jq4.FaXtVZni3cSsWFRMSjQAbjiluPcEvZofwp9OH3t1fyk
X-Content-Type-Options: nosniff
DataServiceVersion: 1.0;
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
X-Powered-By: ASP.NET
Date: Wed, 21 Jan 2015 21:13:25 GMT
Content-Length: 779

--batchresponse_3ac28387-a100-4758-8998-8b9ec36f9fdc
Content-Type: multipart/mixed; boundary=changesetresponse_72ba9a5a-2da3-4d39-ae4f-dd9527efd742--changesetresponse_72ba9a5a-2da3-4d39-ae4f-dd9527efd742
Content-Type: application/http
Content-Transfer-Encoding: binary

HTTP/1.1 404 Not Found
X-Content-Type-Options: nosniff
DataServiceVersion: 3.0;
Content-Type: application/json;odata=minimalmetadata;streaming=true;charset=utf-8

{
  "odata.error":
    {
      "code":"Request_ResourceNotFound",
      "message":
        {
          "lang":"en",
          "value":"Resource 'eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee' does not exist or one of its queried reference-property objects are not present."
        }
    }
}
--changesetresponse_72ba9a5a-2da3-4d39-ae4f-dd9527efd742----batchresponse_3ac28387-a100-4758-8998-8b9ec36f9fdc--

请参考下面的示例,该示例演示了生成上述响应的批处理。 它包含将三个用户添加到组的单个更改集。 最后两个用户的对象 ID 是虚构的: eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee 和 ffffffff-ffff-ffff-ffff-ffffffffffff。 为简洁起见,将省略批处理 URL 和相关联的请求标头。

--batch_36522ad7-fc75-4b56-8c71-56071383e77b 
Content-Type: multipart/mixed; boundary=changeset_5a769eb2-d1a7-4a10-94f6-d1a5ed5c4bc0 
Content-Length: 1432

--changeset_5a769eb2-d1a7-4a10-94f6-d1a5ed5c4bc0 
Content-Type: application/http 
Content-Transfer-Encoding: binary 

POST /contoso.onmicrosoft.com/groups/fc15e7ef-993f-4865-bf37-317d9b8017b8/$links/members?api-version=1.5 HTTP/1.1
Content-Type: application/json
Accept: application/json
Content-Length: 112
Host: graph.windows.net

{
  "url":"https://graph.windows.net/contoso.onmicrosoft.com/users/a71e4d1c-ce99-40dc-8d4b-390eac63e039"
}

--changeset_5a769eb2-d1a7-4a10-94f6-d1a5ed5c4bc0 
Content-Type: application/http 
Content-Transfer-Encoding: binary 

POST /contoso.onmicrosoft.com/groups/fc15e7ef-993f-4865-bf37-317d9b8017b8/$links/members?api-version=1.5 HTTP/1.1
Content-Type: application/json
Accept: application/json
Content-Length: 112
Host: graph.windows.net

{
  "url":"https://graph.windows.net/contoso.onmicrosoft.com/users/eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee
"
}

--changeset_5a769eb2-d1a7-4a10-94f6-d1a5ed5c4bc0 
Content-Type: application/http 
Content-Transfer-Encoding: binary 

POST /contoso.onmicrosoft.com/groups/fc15e7ef-993f-4865-bf37-317d9b8017b8/$links/members?api-version=1.5 HTTP/1.1
Content-Type: application/json
Accept: application/json
Content-Length: 112
Host: graph.windows.net

{
  "url":"https://graph.windows.net/contoso.onmicrosoft.com/users/ffffffff-ffff-ffff-ffff-ffffffffffff"
}

--changeset_5a769eb2-d1a7-4a10-94f6-d1a5ed5c4bc0----batch_36522ad7-fc75-4b56-8c71-56071383e77b--

其他资源