维护 Exchange 中的一组订阅和邮箱服务器之间的相关性Maintain affinity between a group of subscriptions and the Mailbox server in Exchange

了解有关维护一组订阅和邮箱服务器之间的相关性的信息。Find out about maintaining the affinity between a group of subscriptions and the Mailbox server.

相关性是对特定邮箱服务器的一系列请求和响应消息的关联。Affinity is the association of a sequence of request and response messages with a particular Mailbox server. 对于 Exchange 中的大多数功能,相关性由服务器处理。For most functionality in Exchange, affinity is handled by the server. 但是,通知是一个例外。Notifications, however, are an exception. 客户端负责维护邮箱服务器的与通知订阅的关联。The client is responsible for maintaining the affinity with the Mailbox server for notification subscriptions. 此相关性使客户端和服务器之间的负载平衡器和客户端访问服务器能够将通知订阅和相关请求路由到维护订阅的邮箱服务器。This affinity enables the load balancer and Client Access servers between the client and the server to route notification subscriptions and related requests to the Mailbox server that maintains the subscription. 如果没有关联,请求可能会路由到不包含客户端订阅的不同邮箱服务器,这可能会导致返回ErrorSubscriptionNotFound错误。Without affinity, the request might get routed to a different Mailbox server that does not include the client's subscriptions, which can cause an ErrorSubscriptionNotFound error to be returned.

相关性是如何维护的?How is affinity maintained?

Exchange 中的相关性是基于 cookie 的。Affinity in Exchange is cookie based. 客户端通过在订阅请求中包含特定标头来触发 cookie 的创建,然后订阅响应包含 cookie。The client triggers the creation of the cookie by including specific headers in the subscription request, and then the subscription response contains the cookie. 然后,客户端在后续请求中发送该 cookie,以确保将该请求路由到正确的邮箱服务器。The client then sends that cookie in subsequent requests to ensure that the request is routed to the right Mailbox server.

更具体地说,通过以下方式处理 Exchange 中的相关性:More specifically, affinity in Exchange is handled by the following:

  • X-anchormailbox —初始订阅请求中包含的 HTTP 标头。X-AnchorMailbox — An HTTP header that is included in the initial subscription request. 它标识与同一邮箱服务器共享相关性的一组邮箱中的第一个邮箱。It identifies the first mailbox in a group of mailboxes that share affinity with the same Mailbox server.

  • PreferServerAffinity —使用 X-anchormailbox 标头的初始订阅请求中包含的 HTTP 标头,并将其设置为 true,以指示客户端请求与邮箱服务器一起维护相关性。X-PreferServerAffinity — An HTTP header that is included in the initial subscription request with the X-AnchorMailbox header and is set to true to indicate that the client is requesting that affinity be maintained with the Mailbox server.

  • BackEndOverrideCookie —初始订阅响应中包含的 cookie,其中包含负载平衡器和客户端访问服务器用于将后续请求路由到同一个邮箱服务器的 cookie。X-BackEndOverrideCookie — A cookie that is included in the initial subscription response and contains a cookie that the load balancer and Client Access server use to route subsequent requests to the same Mailbox server.

如何使用 EWS 托管 API 或 EWS 维护相关性?How do I maintain affinity by using the EWS Managed API or EWS?

您可以使用相同的步骤来维护多个邮箱订阅及其邮箱服务器的相关性,而不管您使用的是流式传输、请求通知还是推送通知,无论您是面向 Exchange 本地服务器还是 Exchange Online,都是如此。You can use the same steps to maintain affinity for multiple mailbox subscriptions and their Mailbox servers, regardless of whether you are using streaming, pull, or push notifications, and regardless of whether you're targeting an Exchange on-premises server or Exchange Online.

  1. 对于每个邮箱,调用自动发现并获取 GroupingInformation 和 ExternalEwsUrl 用户设置。For each mailbox, call Autodiscover and get the GroupingInformation and ExternalEwsUrl user settings. 对于 SOAP 自动发现,可以使用Setting元素,对于 POX 自动发现,可以使用GroupingInformation元素。For SOAP Autodiscover, you use the Setting element, and for POX Autodiscover, you use the GroupingInformation element.

  2. 使用自动发现响应中的 GroupingInformation 和 ExternalEwsUrl 设置,将具有相同 ExternalEwsUrl 和 GroupingInformation 串联值的邮箱放在同一组中。Using the GroupingInformation and ExternalEwsUrl settings from the Autodiscover responses, place mailboxes with the same ExternalEwsUrl and GroupingInformation concatenated value in the same group. 如果任何组的邮箱数超过200,则将组进一步分解,以便每个组的邮箱数不超过200。If any groups have more than 200 mailboxes, break the groups down further so that each group has no more than 200 mailboxes.

  3. 为过程的其余部分创建和使用一个ExchangeService对象。Create and use one ExchangeService object for the rest of the procedure. 当您使用相同的ExchangeService对象时,会自动维护 cookie 和标题(设置时)。When you use the same ExchangeService object, cookies and headers (when they are set) are automatically maintained. 请注意,如果不打算将流式订阅分组到单个连接中,则可以为每个模拟用户自由创建不同的ExchangeService对象。Note that if you do not intend to group streaming subscriptions into a single connection, you are free to create a different ExchangeService object for each impersonated user.

  4. 为用户发送订阅请求,在按字母顺序对组中的所有用户进行排序(我们将把此用户称为定位邮箱用户)时,首先显示该用户的用户名。Send a subscription request for the user whose user name appears first when all users in the group are sorted alphabetically (we'll refer to this user as the anchor mailbox user). 请执行以下操作:Do the following:

  • 包含 X-anchormailbox 标头,其值设置为定位邮箱用户的 SMTP 地址。Include the X-AnchorMailbox header with a value set to the SMTP address of the anchor mailbox user.

  • 包含值设置为 true 的 PreferServerAffinity 标头。Include the X-PreferServerAffinity header with a value set to true.

  • 使用ApplicationImpersonation角色( ExchangeImpersonation类型)。Use the ApplicationImpersonation role (the ExchangeImpersonation type).

  1. 在订阅响应中,获取 X-BackEndOverrideCookie 值。In the subscription response, get the X-BackEndOverrideCookie value. 在此组中的用户的每个后续订阅请求中包含此值。Include this value in each of the subsequent subscription requests for users in this group.

  2. 对于组中的每个其他用户,发送订阅请求并执行以下操作:For each additional user in the group, send a subscription request and do the following:

  • 包含一个设置为组的定位邮箱用户的 SMTP 地址的值的 X-anchormailbox 标头。Include the X-AnchorMailbox header with a value set to the SMTP address of the anchor mailbox user for the group.

  • 包含值设置为 true 的 PreferServerAffinity 标头。Include the X-PreferServerAffinity header with a value set to true.

  • 包括在锚定邮箱用户的订阅响应中返回的 X-BackEndOverrideCookie。Include the X-BackEndOverrideCookie that was returned in the anchor mailbox user's subscription response.

  • 使用ApplicationImpersonation角色( ExchangeImpersonation类型)。Use the ApplicationImpersonation role (the ExchangeImpersonation type).

    请注意,服务器会将 PreferServerAffinity 和 BackendOverrideCookie 值一起使用,以执行到邮箱服务器的路由。Note that the server uses the X-PreferServerAffinity and X-BackendOverrideCookie values together to perform the routing to the mailbox server. X-X-anchormailbox 标头也是必需的,但如果其他两个值有效,则服务器将忽略该标头。The X-AnchorMailbox header is also required, but is ignored by the server if the other two values are valid. 如果 X-X-anchormailbox 和 X-PreferServerAffinity 位于请求中,并且不包含 X-BackendOverrideCookie,则使用 X-X-anchormailbox 值路由请求。If X-AnchorMailbox and X-PreferServerAffinity are in a request and X-BackendOverrideCookie is not included, the X-AnchorMailbox value is used to route the requests.

    由于 PreferServerAffinity 和 X BackendOverrideCookie 值执行路由,如果定位邮箱移动到另一个组或服务器,则逻辑不会更改,因为 X-BackendOverrideCookie 会将请求路由到组的正确服务器。Because the X-PreferServerAffinity and X-BackendOverrideCookie values perform the routing, if the anchor mailbox ever moves to another group or server, the logic does not change because the X-BackendOverrideCookie will route the request to the correct server for the group.

  1. 向组发送单个GetStreamingEventsGetEvents请求,并执行以下操作:Send a single GetStreamingEvents or GetEvents requests for the group, and do the following:
  • 在组中每个邮箱的各个订阅响应中包括返回的SubscriptionId值。Include the SubscriptionId values returned in each of the individual subscription responses for mailboxes in the group.

  • 如果组中存在多于200个订阅,请创建多个请求。If more than 200 subscriptions exist for the group, create multiple requests. 要包含在请求中的最大订阅数值为200。The maximum number of SubscriptionId values to include in a request is 200.

  • 如果需要的连接数超过了目标邮箱可用的数目,请使用服务帐户模拟组的定位邮箱;否则,请勿使用模拟。If you need more connections than are available to the target mailbox, use the service account to impersonate the anchor mailbox for the group; otherwise, do not use impersonation. 理想情况下,您想要模拟每个GetStreamingEventsGetEvents请求的唯一邮箱,以便您永远不会遇到限制限制。Ideally, you want to impersonate a unique mailbox per GetStreamingEvents or GetEvents request so that you never encounter throttling limits.

  • 如果需要的连接数多于目标邮箱可用的连接数,请使用 ApplicationImpersonation;否则,请不要使用 ApplicationImpersonation。Use ApplicationImpersonation if you need more connections than are available to the target mailbox; otherwise, do not use ApplicationImpersonation.

  • 包含 PreferServerAffinity 标头并将其设置为 true。Include the X-PreferServerAffinity header and set it to true. 如果使用的是在步骤2中创建的ExchangeService对象,则此值将自动包括在内。This value is automatically included if you are using the ExchangeService object that you created in step 2.

  • 包含组的 X-BackEndOverrideCookie (在锚点邮箱用户的订阅响应中返回的 X-BackEndOverrideCookie)。Include the X-BackEndOverrideCookie for the group (the X-BackEndOverrideCookie that was returned in the anchor mailbox user's subscription response). 如果使用的是在步骤2中创建的ExchangeService对象,则此值将自动包括在内。This value is automatically included if you are using the ExchangeService object that you created in step 2.

  1. 将返回的事件传递到单独的线程以进行处理。Pass the returned events to a separate thread for processing.

我需要考虑哪些限制值?What throttling values do I need to take into consideration?

在规划通知实现过程中,需要考虑两个值:连接数和订阅数。As you plan your notification implementation, you'll want to take two values into consideration: the number of connections, and the number of subscriptions. 下表列出了每个限制设置的默认值以及这些设置的使用方式。The following table lists the default values for each throttling setting and how the settings are used. 对于每个值,将预算分配给目标邮箱。For each value, the budget is allocated to the target mailbox. 因此,在很多情况下,使用模拟获取额外的连接是必需的步骤。For this reason, using impersonation to gain additional connections is a required step in many scenarios.

表1。默认限制值Table 1. Default throttling values

注意事项区域Area of consideration 限制设置Throttling setting 默认值Default value 说明Description
流式连接Streaming connections
默认悬挂连接限制Default hanging connection limit
10(适用于 Exchange Online)10 for Exchange Online
3对于 Exchange 20133 for Exchange 2013
一个帐户可以一次在服务器上打开的并发流式连接的最大数量。The maximum number of concurrent streaming connections that an account can have open on the server at one time. 若要在此限制内工作,请使用为目标邮箱分配了 ApplicationImpersonation 角色的服务帐户,并在获取流式处理事件时模拟每个订阅 ID 组中的第一个用户。To work within this limit, use a service account with the ApplicationImpersonation role assigned for the target mailboxes, and impersonate the first user in each subscription ID group when getting streamed events.
Pull 或 push 连接Pull or push connections
限制EWSMaxConcurrency
2727
一个帐户可以一次在服务器上打开的并发拉取或推送连接(已接收但尚未响应的请求)的最大数量。The maximum number of concurrent pull or push connections (requests that have been received but not yet responded to) that an account can have open on the server at one time.
订阅Subscriptions
EWSMaxSubscriptionsEWSMaxSubscriptions
20 for Exchange Online20 for Exchange Online
适用于 Exchange 2013 的50005000 for Exchange 2013
一个帐户一次可以拥有的最大 nonexpired 订阅数。The maximum number of nonexpired subscriptions that an account can have at one time. 在服务器上创建订阅时,此值会减少。This value is decremented when the subscription is created on the server.

下面的示例展示了在为目标邮箱分配了ApplicationImpersonation角色的任何目标邮箱和服务帐户之间如何处理预算。The following example shows how budgets are handled between any target mailbox and the service account that has the ApplicationImpersonation role assigned for the target mailboxes.

  • ServiceAccount1 (sa1)模拟许多用户(m1、m2、m3 等)并为每个邮箱创建订阅。ServiceAccount1 (sa1) impersonates many users (m1, m2, m3, and so on) and creates subscriptions for each mailbox. 请注意,在创建订阅时,订阅所有者是 sa1,因此当 sa1 打开与订阅的连接时,EWS 将强制这些订阅归 sa1 所有。Note that when the subscriptions are created, the subscription owner is sa1, so when sa1 opens a connection with the subscriptions, EWS enforces that the subscriptions are owned by sa1.

  • Sa1 可以通过以下方式打开连接:Sa1 can open the connection in the following ways:

  1. 不进行模拟,因此将针对 sa1 对连接收费。Without impersonation, so the connection is charged against sa1.

  2. 通过模拟任何用户—例如 m1,以便根据 m1's 预算的副本对连接进行计费。By impersonating any of the users — m1 for example — so that the connection is charged against a copy of m1's budget. (M1 本身可以通过使用 Exchange Online 打开10个连接,所有服务帐户模拟 M1 可以使用复制的预算打开10个连接。)(M1 itself can open ten connections by using Exchange Online, and all service accounts impersonating m1 can open ten connections by using the copied budget.)

  • 如果点击了连接限制,则可以使用以下解决方法:If the connection limit is hit, the following workarounds are available:

    • 如果使用选项1,则管理员可以创建多个服务帐户以模拟其他用户。If option 1 is used, the administrator can create multiple service accounts to impersonate additional users.

    • 如果使用选项2,则代码可以模拟其他用户(例如,m2)。If option 2 is used, the code can impersonate another user — m2 for example.

示例:维护一组订阅与邮箱服务器之间的相关性Example: Maintaining affinity between a group of subscriptions and the Mailbox server

好了,让我们看看它在操作中。Okay, let's see it in action. 下面的代码示例演示如何对用户进行分组,以及如何使用 X-anchormailbox 和 PreferServerAffinity 标头和 X BackendOverrideCookie cookie 维护与邮箱服务器的相关性。The following code example shows you how to group users and use the X-AnchorMailbox and X-PreferServerAffinity headers and the X-BackendOverrideCookie cookie to maintain affinity with the Mailbox server. 由于标头和 cookie 在相关性情景中是主要的重要性,因此本示例重点介绍 EWS XML 请求和响应。Because the headers and the cookie are of primary importance in the affinity story, this example focuses on the EWS XML requests and responses. 若要使用 EWS 托管 API 创建订阅请求和响应的正文,请参阅通过 exchange中的 ews 在 exchange 中使用 ews有关邮箱事件的拉取通知中的有关邮箱事件的流通知。To use the EWS Managed API to create the body of the subscription requests and responses, see Stream notifications about mailbox events by using EWS in Exchange and Pull notifications about mailbox events by using EWS in Exchange. 本节包含特定于维护相关性并将邮件头添加到请求中的其他步骤。This section includes additional steps particular to maintaining affinity and adding the headers to your requests.

此示例包含四个用户: alfred@contoso.com、alisa@contoso.com、ronnie@contoso.com 和 sadie@contoso.com。This example has four users: alfred@contoso.com, alisa@contoso.com, ronnie@contoso.com, and sadie@contoso.com. 下图显示了用户的 GroupingInformation 和 ExternalEwsUrl自动发现设置The following figure shows the GroupingInformation and ExternalEwsUrl Autodiscover settings for the users.

图1。用于对邮箱进行分组的自动发现设置Figure 1. Autodiscover settings used to group mailboxes

此表格显示每个用户的 GroupingInformation 和 ExternalEwsUrl 值。

使用自动发现响应中的设置,将按 GroupingInformation 和 ExternalEwsUrl 设置的串联值对邮箱进行分组。Using the settings from the Autodiscover responses, the mailboxes are grouped by the concatenated value of the GroupingInformation and ExternalEwsUrl settings. 在此示例中,Alfred 和 Sadie 具有相同的值,因此它们位于一个组中,Alisa 和 Ronnie 共享相同的值,因此它们位于另一个组中。In this example, Alfred and Sadie have the same values, so they are in one group, and Alisa and Ronnie share the same values, so they are in another group.

图2。创建邮箱组Figure 2. Creating mailbox groups

此表格显示如何使用 Autodiscover 设置创建邮箱组。

出于本示例的目的,我们将重点放在 A 组上。对组 B 使用相同的步骤,但对该组使用不同的 X X-anchormailbox 值。For the purpose of this example, we'll focus on Group A. We would use the same steps for group B, but use a different X-AnchorMailbox value for that group.

使用ApplicationImpersonation为定位邮箱(alfred@contoso.com)创建订阅请求,并将 x-x-anchormailbox 标头设置为其电子邮件地址,并将 x-PreferServerAffinity 标头值设置为 true。Using ApplicationImpersonation, create the subscription request for the anchor mailbox (alfred@contoso.com), with the X-AnchorMailbox header set to the their email address and an X-PreferServerAffinity header value of true. 设置这两个标头值将触发服务器为响应创建 X-BackEndOverrideCookie。Setting these two header values will trigger the server to create an X-BackEndOverrideCookie for the response.

如果使用 EWS 托管 API,请使用HttpHeadersadd方法将这两个标头添加到订阅请求中,如下所示。If you're using the EWS Managed API, use the HttpHeadersAdd method to add the two headers to your subscription request, as shown.

service.HttpHeaders.Add("X-AnchorMailbox", Mailbox.SMTPAddress);
service.HttpHeaders.Add("X-PreferServerAffinity", "true");

因此,Alfred 的订阅请求如下所示。So Alfred's subscription request looks like this.

POST https://outlook.office365.com/EWS/Exchange.asmx HTTP/1.1
Content-Type: text/xml; charset=utf-8
Accept: text/xml
User-Agent: ExchangeServicesClient/15.00.0516.014
X-AnchorMailbox: alfred@contoso.com
X-PreferServerAffinity: true
Host: outlook.office365.com
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:m="https://schemas.microsoft.com/exchange/services/2006/messages" xmlns:t="https://schemas.microsoft.com/exchange/services/2006/types" xmlns:soap="https://schemas.xmlsoap.org/soap/envelope/">
  <soap:Header>
    <t:RequestServerVersion Version="Exchange2013" />
    <t:ExchangeImpersonation>
      <t:ConnectingSID>
        <t:SmtpAddress>alfred@contoso.com</t:SmtpAddress>
      </t:ConnectingSID>
    </t:ExchangeImpersonation>
  </soap:Header>
  <soap:Body>
    <m:Subscribe>
      <m:StreamingSubscriptionRequest>
        <t:FolderIds>
          <t:DistinguishedFolderId Id="inbox" />
        </t:FolderIds>
        <t:EventTypes>
          <t:EventType>NewMailEvent</t:EventType>
        </t:EventTypes>
      </m:StreamingSubscriptionRequest>
    </m:Subscribe>
  </soap:Body>
</soap:Envelope>

下面的 XML 消息是对 Alfred 的订阅请求的响应,它包含 X-BackEndOverrideCookie。The following XML message is the response to Alfred's subscription request, and it includes the X-BackEndOverrideCookie. 为此组中的用户的所有后续请求重新发送此 cookie。Resend this cookie for all subsequent requests for users in this group. 请注意,该响应还包含其他 cookie,如 Exchange 2010 使用的 exchangecookie cookie。Notice that the response also contains additional cookies, such as the exchangecookie cookie used by Exchange 2010. Exchange Online、Exchange Online (作为 Office 365 的一部分)以及从 Exchange 2013 开始的 Exchange 版本,如果在后续订阅请求中包含,则忽略 exchangecookie。Exchange Online, Exchange Online as part of Office 365, and versions of Exchange starting with Exchange 2013, ignore exchangecookie if it is included in subsequent subscription requests.

HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Set-Cookie: exchangecookie=ddb8c383aef34c7694132aa679744feb; expires=Thu, 25-Sep-2014 18:42:45 GMT; path=/;
    HttpOnly
Set-Cookie: X-BackEndOverrideCookie=CO1PR06MB222.namprd06.prod.outlook.com~1941996295; path=/; secure; HttpOnly
Set-Cookie: X-BackEndCookie=alfred@contoso.com=Ox8XKzcXLxg==; 
    expires=Wed, 25-Sep-2013 18:52:49 GMT; path=/EWS; secure; HttpOnly
<?xml version="1.0" encoding="utf-8"?>
<s:Envelope xmlns:s="https://schemas.xmlsoap.org/soap/envelope/">
  <s:Header>
    <h:ServerVersionInfo MajorVersion="15"
                         MinorVersion="0"
                         MajorBuildNumber="775"
                         MinorBuildNumber="7"
                         Version="V2_4"
                         xmlns:h="https://schemas.microsoft.com/exchange/services/2006/types"
                         xmlns="https://schemas.microsoft.com/exchange/services/2006/types"
                         xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
  </s:Header>
  <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <m:SubscribeResponse xmlns:m="https://schemas.microsoft.com/exchange/services/2006/messages"
                         xmlns:t="https://schemas.microsoft.com/exchange/services/2006/types">
      <m:ResponseMessages>
        <m:SubscribeResponseMessage ResponseClass="Success">
          <m:ResponseCode>NoError</m:ResponseCode>
          <m:SubscriptionId>JgBjbzFwcjA2bWIyMjIubmFtcHJkMDYucHJvZC5vdXRsb29rLmNvbRAAAAAUeGk+7JFdSaFM8/NI/gQQpVdgZX6H0Ag=</m:SubscriptionId>
        </m:SubscribeResponseMessage>
      </m:ResponseMessages>
    </m:SubscribeResponse>
  </s:Body>
</s:Envelope>

使用来自 Alfred 的响应和 X X-anchormailbox 标头的 BackEndOverrideCookie,订阅请求是为 Sadie 创建的。 Sadie 的订阅请求的另一个成员如下所示。Using the X-BackEndOverrideCookie from Alfred's response and the X-AnchorMailbox header, the subscription request is created for Sadie, the other member of Group A. Sadie's subscription request looks like this.

POST https://outlook.office365.com/EWS/Exchange.asmx HTTP/1.1
Content-Type: text/xml; charset=utf-8
Accept: text/xml
User-Agent: ExchangeServicesClient/15.00.0516.014
X-AnchorMailbox: alfred@contoso.com
X-PreferServerAffinity: true
Host: outlook.office365.com
Cookie: X-BackEndOverrideCookie=CO1PR06MB222.namprd06.prod.outlook.com~1941996295
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:m="https://schemas.microsoft.com/exchange/services/2006/messages" xmlns:t="https://schemas.microsoft.com/exchange/services/2006/types" xmlns:soap="https://schemas.xmlsoap.org/soap/envelope/">
  <soap:Header>
    <t:RequestServerVersion Version="Exchange2013" />
    <t:ExchangeImpersonation>
      <t:ConnectingSID>
        <t:SmtpAddress>sadie@contoso.com </t:SmtpAddress>
      </t:ConnectingSID>
    </t:ExchangeImpersonation>
  </soap:Header>
  <soap:Body>
    <m:Subscribe>
      <m:StreamingSubscriptionRequest>
        <t:FolderIds>
          <t:DistinguishedFolderId Id="inbox" />
        </t:FolderIds>
        <t:EventTypes>
          <t:EventType>NewMailEvent</t:EventType>
        </t:EventTypes>
      </m:StreamingSubscriptionRequest>
    </m:Subscribe>
  </soap:Body>
</soap:Envelope>

Sadie 的订阅响应如下所示。Sadie's subscription response looks like this. 请注意,它不包含 X-BackEndOverrideCookie。Note that it does not include the X-BackEndOverrideCookie. 客户端负责为未来的请求缓存该值。The client is responsible for caching that value for future requests.

HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Set-Cookie: exchangecookie=640ea858f69d47ff8cce8b44c337f6d9; path=/
Set-Cookie: X-BackEndCookie=alfred@contoso.com=Ox8XKzcXLxg==; 
   expires= Wed, 25-Sep-2013 18:53:06 GMT; path=/EWS; secure; HttpOnly
<?xml version="1.0" encoding="utf-8"?>
<s:Envelope xmlns:s="https://schemas.xmlsoap.org/soap/envelope/">
  <s:Header>
    <h:ServerVersionInfo MajorVersion="15"
                         MinorVersion="0"
                         MajorBuildNumber="775"
                         MinorBuildNumber="7"
                         Version="V2_4"
                         xmlns:h="https://schemas.microsoft.com/exchange/services/2006/types"
                         xmlns="https://schemas.microsoft.com/exchange/services/2006/types"
                         xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
  </s:Header>
  <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <m:SubscribeResponse xmlns:m="https://schemas.microsoft.com/exchange/services/2006/messages"
                         xmlns:t="https://schemas.microsoft.com/exchange/services/2006/types">
      <m:ResponseMessages>
        <m:SubscribeResponseMessage ResponseClass="Success">
          <m:ResponseCode>NoError</m:ResponseCode>
          <m:SubscriptionId>JgBjbzFwcjA2bWIyMjIubmFtcHJkMDYucHJvZC5vdXRsb29rLmNvbRAAAAB4EQOy2pfrQJfM3hzs/nZJIZssan6H0Ag=</m:SubscriptionId>
        </m:SubscribeResponseMessage>
      </m:ResponseMessages>
    </m:SubscribeResponse>
  </s:Body>
</s:Envelope>

使用订阅响应中的SubscriptionId值,为组中的所有订阅创建了GetStreamingEvents操作请求。Using the SubscriptionId values from the subscription responses, a GetStreamingEvents operation request was created for all the subscriptions in the group. 由于此组中的订阅数少于200个,因此将在一个请求中发送这些订阅。Because there are less than 200 subscriptions in this group, they are all sent in one request. 将 X-PreferServerAffinity 标头设置为 true,并包含 X-BackEndOverrideCookie。The X-PreferServerAffinity header is set to true and the X-BackEndOverrideCookie is included.

POST https://outlook.office365.com/EWS/Exchange.asmx HTTP/1.1
Content-Type: text/xml; charset=utf-8
Accept: text/xml
User-Agent: ExchangeServicesClient/15.00.0516.014
X-AnchorMailbox: alfred@contoso.com
X-PreferServerAffinity: true
Host: outlook.office365.com
Cookie: X-BackEndOverrideCookie=CO1PR06MB222.namprd06.prod.outlook.com~1941996295
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:m="https://schemas.microsoft.com/exchange/services/2006/messages" xmlns:t="https://schemas.microsoft.com/exchange/services/2006/types" xmlns:soap="https://schemas.xmlsoap.org/soap/envelope/">
  <soap:Header>
    <t:RequestServerVersion Version="Exchange2013" />
    <t:ExchangeImpersonation>
      <t:ConnectingSID>
        <t:SmtpAddress>sadie@contoso.com</t:SmtpAddress>
      </t:ConnectingSID>
    </t:ExchangeImpersonation>
  </soap:Header>
  <soap:Body>
    <m:GetStreamingEvents>
      <m:SubscriptionIds>
        <t:SubscriptionId>JgBjbzFwcjA2bWIyMjIubmFtcHJkMDYucHJvZC5vdXRsb29rLmNvbRAAAAB4EQOy2pfrQJfM3hzs/nZJIZssan6H0Ag=</t:SubscriptionId>
        <t:SubscriptionId>JgBjbzFwcjA2bWIyMjIubmFtcHJkMDYucHJvZC5vdXRsb29rLmNvbRAAAAAUeGk+7JFdSaFM8/NI/gQQpVdgZX6H0Ag=</t:SubscriptionId>
      </m:SubscriptionIds>
      <m:ConnectionTimeout>10</m:ConnectionTimeout>
    </m:GetStreamingEvents>
  </soap:Body>
</soap:Envelope>

然后,将返回的事件传递给单独的线程以进行处理。The returned events are then passed to a separate thread for processing.

关系如何更改?How has affinity changed?

在 Exchange 2010 中,订阅在客户端访问服务器上进行维护,如图3中所示。In Exchange 2010, subscriptions are maintained on the Client Access server, as shown in Figure 3. 在低于 Exchange 2010 的 Exchange 版本中,订阅在邮箱服务器上进行维护,如图4所示。In versions of Exchange later than Exchange 2010, subscriptions are maintained on the Mailbox server, as shown in Figure 4.

图3。在 Exchange 2010 中维护相关性的过程Figure 3. Process for maintaining affinity in Exchange 2010

此插图显示 Exchange 2010 中客户端访问服务器上的活动订阅表的维护方式。

图4。在 Exchange Online 和 Exchange 2013 中维护相关性的过程Figure 4. Process for maintaining affinity in Exchange Online and Exchange 2013

此插图显示 Exchange Server 和 Exchange Online 中的负载平衡器和客户端访问服务器路由如何向维护活动订阅表的邮箱服务器发出请求。

在 Exchange 2010 中,客户端只知道负载平衡器的地址,服务器返回的 exchangecookie 确保将请求路由到正确的客户端访问服务器。In Exchange 2010, the client only knows the address of the load balancer, and the exchangecookie that is returned by the server ensures that the request is routed to the right Client Access server. 但是,在更高版本中,负载平衡器和客户端访问服务器角色都必须在到达邮箱服务器之前适当地路由请求。However, in later versions, the load balancer and the Client Access server roles both have to route the requests appropriately before they get to the Mailbox server. 为此,需要额外的信息,这就是引入新标头和 cookie 的原因。To do that, additional information is required, which is why the new headers and cookie were introduced. Exchange 中的文章通知订阅、邮箱事件和 EWS说明了如何在 exchange 2013 中维护订阅。The article Notification subscriptions, mailbox events, and EWS in Exchange explains how subscriptions are maintained in Exchange 2013.

您可能会注意到,Exchange 2010 使用的 exchangecookie 仍将由更高版本返回。You might notice that the exchangecookie that Exchange 2010 uses is still returned by later versions. 不会对在请求中包含此 cookie 造成危害,但更高版本的 Exchange 将忽略它。There's no harm in including this cookie in requests, but later versions of Exchange ignore it.

另请参阅See also