Exchange Web Service(EWS) 协议
EWS是微软实现的一种客户端和服务器之间的交换信息的协议。Exchange Server提供了包括从电子邮件、会议安排、团体日程管理、任务管理、文档管理、实时会议和工作流等丰富的协作应用。
EWS基于标准的web service, 使用HTTP+XML+SOAP来传输消息的。一条 SOAP 消息就是一个普通的 XML 文档,包含下列元素:
必需的 Envelope 元素,可把此 XML 文档标识为一条 SOAP 消息可选的 Header 元素,包含头部信息必需的 Body 元素,包含所有的调用和响应信息可选的 Fault 元素所发生错误的信息,提供有关在处理此消息
EWS的SOAP消息,Header中指明使用的EWS版本信息:
<s:Header>
<t:RequestServerVersion s:mustUnderstand="1" Version="Exchange2010_SP1"/>
</s:Header>
Body中是真正的命令信息,指明要调用的接口和使用的参数:
<s:Body>
<m:GetFolder>
<m:FolderShape>
<t:BaseShape>IdOnly
</t:BaseShape>
<t:AdditionalProperties>
<t:FieldURI FieldURI="folder:DistinguishedFolderId"/>
</t:AdditionalProperties>
</m:FolderShape>
<m:FolderIds>
<t:DistinguishedFolderId Id="deleteditems"/>
</m:FolderIds>
</m:GetFolder>
</s:Body>
当请求成功是,响应的内容也是放在Body当中:
<s:Body>
<m:GetFolderResponse xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types">
<m:ResponseMessages>
<m:GetFolderResponseMessage ResponseClass="Success">
<m:ResponseCode>NoError
</m:ResponseCode>
<m:Folders>
<t:Folder>
<t:FolderId Id="AQMkADAwATMwMAItZDAyNi05ODYxLTAwAi0wMAoALgAAA428HhUZWjFJpUSRJeFqnBwBAHQq8eP3dM1JkMChdMfyLSgAAAIBCgAAAA==" ChangeKey="AQAAABYAAAB0KvHj93TNSZDAoXTH8i0oAAB17L8t" />
</t:Folder>
</m:Folders>
</m:GetFolderResponseMessage>
</m:ResponseMessages>
</m:GetFolderResponse>
</s:Body>
EWS有多个实现版本,每个版本支持的请求都描述在以下三个文件中:
services.wsdl : 定义了客户端和服务器之间支持的消息协议Messages.xds: 定义了SOAP消息请求和响应的信息类型Types.xds:定义了SOAP消息使用的数据类型
要访问EWS服务器, 可以用这三个文件自动生成soap访问接口,但是生成的接口可读性比较差,使用起来很不方便。所以在我的项目中,我直接拼装SOAP消息来构建我的请求和解析服务器的响应。
在邮箱客户端中, 主要涉及到的操作如下表所示:
folder操作item操作
FindFolder operationCopyItem operationGetFolder operationCreateItem operationCreateFolder operationFindItem operationUpdateFolder operationGetItem operationDeleteFolder operationMoveItem operationSyncFolderHierar operation--SyncFolderItems operation-SendItem operation-UpdateItem operation-GetItem operation
可以看到,EWS支持对邮件folder和邮件对象的增删改查,还支持对folder和item的增量同步。这几个操作是邮箱功能的核心操作,从EWS一开始的版本就开始支持,并不存在版本兼容性的问题。
EWS对每一个folder和item对象都维护了一个changeKey,来表示对象的版本。因此,可以通过changeKey是否变化来判断folder或者item是否发生了改变。EWS为了可以方便的让客户端知道服务器有哪些对象发生了改变,对folder提供了SyncFolderHierar接口用于增量同步folder,对item提供了SyncFolderItems用于增量同步item。这两个增量同步的接口使用了SyncState用于标识同步状态, 如果服务器上的数据发生了改变, 则在响应只返回变更的对象,并将最新的SyncState下发给客户端。下面是这两个命令的具体请求和返回数据示例:
SyncFolderHierar Request
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types">
<soap:Body>
<SyncFolderHierarchy xmlns="http://schemas.microsoft.com/exchange/services/2006/messages">
<FolderShape>
<t:BaseShape>AllProperties
</t:BaseShape>
</FolderShape>
<SyncState>H4sIA=
</SyncState>
</SyncFolderHierarchy>
</soap:Body>
</soap:Envelope>
SyncFolderHierar Response
<?xml version="1.0" encoding="utf-8" ?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Header>
<t:ServerVersionInfo MajorVersion="8" MinorVersion="0"
MajorBuildNumber="628" MinorBuildNumber="0"
xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types" />
</soap:Header>
<soap:Body>
<SyncFolderHierarchyResponse xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages"
xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types"
xmlns="http://schemas.microsoft.com/exchange/services/2006/messages">
<m:ResponseMessages>
<m:SyncFolderHierarchyResponseMessage ResponseClass="Success">
<m:ResponseCode>NoError
</m:ResponseCode>
<m:SyncState>H4sIAAA==
</m:SyncState>
<m:IncludesLastFolderInRange>true
</m:IncludesLastFolderInRange>
<m:Changes>
<t:Create>
<t:Folder>
<t:FolderId Id="AQApAHR=" ChangeKey="AQAAABY" />
<t:ParentFolderId Id="AQApA=" ChangeKey="AQAAAA==" />
<t:FolderClass>IPF.Note
</t:FolderClass>
<t:DisplayName>NewFolder
</t:DisplayName>
<t:TotalCount>0
</t:TotalCount>
<t:ChildFolderCount>0
</t:ChildFolderCount>
<t:UnreadCount>0
</t:UnreadCount>
</t:Folder>
</t:Create>
</m:Changes>
</m:SyncFolderHierarchyResponseMessage>
</m:ResponseMessages>
</SyncFolderHierarchyResponse>
</soap:Body>
</soap:Envelope>
其中IncludesLastFolderInRange节点是告知是否已经返回了所有的变更信息,如果没有,则需要再用新的SyncState再请求多一次,直到IncludesLastFolderInRange节点为true。
SyncFolderItems Request
<?xml version="1.0"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:enc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types" xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages">
<s:Header>
<t:RequestServerVersion s:mustUnderstand="1" Version="Exchange2010_SP1" />
</s:Header>
<s:Body>
<m:SyncFolderItems>
<m:ItemShape>
<t:BaseShape>IdOnly
</t:BaseShape>
<t:IncludeMimeContent>false
</t:IncludeMimeContent>
<t:AdditionalProperties>
<t:FieldURI FieldURI="item:DateTimeSent" />
</t:AdditionalProperties>
</m:ItemShape>
<m:SyncFolderId>
<t:FolderId Id="AQMkADAwATMwMAItZDAyNi05ODYxLTAwAi0wMAoALgAAA428HhUZWjFJpUSRJeFqnBwBAHQq8eP3dM1JkMChdMfyLSgAAAIBCQAAAA==" />
</m:SyncFolderId>
<m:SyncState>H4sIAAAAAAAEAGNgYGcAAotqE0tHE2NTA0ddZ3NHC10TR2djXSdnJ2ddNyMnC2cnczdLU1OD2vBgveDKvOTgksSSVOfEvMSiSgYr0nW65eekpBZ5pjBYkq43LLWoODM/j8GaaK3+QMuKS4JSk1Mzy1JTQjJzU0nwrU9icYlnXnFJYl5yqncqKb71zS9K9SxJzS32zwtOLSpLLSLByXDfhgNxUW5iUTYklrgYGISA0tDwAxkOUskgCJQyAGI9kJrePXKiklGGnktdJqo+zJojw8hQovXx8feSs54TDiwsOf5JVwOkipETiBn4GJhBHG6GoCfHOrpTrngwCAFFeYEYaN1aRgYGX8cAT19HP5AiBjdTtzCQ8gAgVmVAgH9AnIvELwXiTgZMkA00zwyJb2BgYAzEBropBkZmupYWZoa6YK4BEsBwOxMDAwsDg/MDZnZn86B9BwJYpFr185nl2yrt43452fdfahanntrERWEWD
</m:SyncState>
<m:MaxChangesReturned>20
</m:MaxChangesReturned>
</m:SyncFolderItems>
</s:Body>
</s:Envelope>
SyncFolderItems Response
<?xml version="1.0"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<h:ServerVersionInfo xmlns:h="http://schemas.microsoft.com/exchange/services/2006/types" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" MajorVersion="15" MinorVersion="1" MajorBuildNumber="947" MinorBuildNumber="19" Version="V2017_01_07" />
</s:Header>
<s:Body>
<m:SyncFolderItemsResponse xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types">
<m:ResponseMessages>
<m:SyncFolderItemsResponseMessage ResponseClass="Success">
<m:ResponseCode>NoError
</m:ResponseCode>
<m:SyncState>H4sIAAAAAAAEAGNgYGcAAotqE0tHE2NTA0ddZ3NHC10TR2djXSdnJ2ddNyMnC2cnczdLU1OD2vBgveDKvOTgksSSVOfEvMSiSgYr0nW65eekpBZ5pjBYkq43LLWoODM/j8GaaK3+QMuKS4JSk1Mzy1JTQjJzU0nwrU9icYlnXnFJYl5yqncqKb71zS9K9SxJzS32zwtOLSpLLSLByXDfhgNxUW5iUTYklrgYGISA0tDwAxkOUskgCJQyAGI9kJrePXKiklGGnktdJqo+zJojw8hQovXx8feSs54TDiwsOf5JVwOkipETiBn4GJhBHG6GoCfHOrpTrngwCAFFeYEYaN1aRgYGX8cAT19HP5AiBjdTtzCQ8gAgVmVAgH9AnIvELwXiTgZMkA00zwyJb2BgYAzEBropBkZmupYWZoa6YK4BEsBwOxMDAwsDg/MDZnZn86B9BwJYpFr185nlwxyDzC0CWBQuJ2YxK6W7BvHwBzCretwLausPYLZeEhJ0/EQAs8s9saBbtwNY3DZHvGH2U4oIEpUMYA58eDzI1S2AOWTZsiA3zwDm8HtNQU6uAcwRLPeCGpsCmKPcHgd9+h4QgM0hzNx7vwU9egK0YZOnkxdTAJP93qAVf1cCrXZ5X+50lwlo1VG/X8x+5hlOrauAVv2ocZJiAlq1b7fTOi2gVd+2OjEB6QhZU6elQPGoBHenGasYF2G3LAgUaSVT3HcGMNwLYd+tVs/hO1n/X9VcpR972cDBychQzMDQAADqPT+hzwMAAA==
</m:SyncState>
<m:IncludesLastItemInRange>true
</m:IncludesLastItemInRange>
<m:Changes>
<t:Create>
<t:MeetingRequest>
<t:ItemId Id="AQMkADAwATMwMAItZDAyNi05ODYxLTAwAi0wMAoARgAAA428HhUZWjFJpUSRJeFqnBwHAHQq8eP3dM1JkMChdMfyLSgAAAIBCQAAAHQq8eP3dM1JkMChdMfyLSgAAAAHQze+AAAA" ChangeKey="CwAAABYAAAB0KvHj93TNSZDAoXTH8i0oAAALvfbi" />
<t:DateTimeSent>2016-09-26T04:36:53Z
</t:DateTimeSent>
</t:MeetingRequest>
</t:Create>
<t:Update>
<t:MeetingRequest>
<t:ItemId Id="AQMkADAwATMwMAItZDAyNi05ODYxLTAwAi0wMAoARgAAA428HhUZWjFJpUSRJeFqnBwHAHQq8eP3dM1JkMChdMfyLSgAAAIBCQAAAHQq8eP3dM1JkMChdMfyLSgAAAAHQze/AAAA" ChangeKey="CwAAABYAAAB0KvHj93TNSZDAoXTH8i0oAAALvfbj" />
<t:DateTimeSent>2016-09-26T04:38:57Z
</t:DateTimeSent>
</t:MeetingRequest>
</t:Update>
<t:Delete>
<t:MeetingRequest>
<t:ItemId Id="AQMkADAwATMwMAItZDAyNi05ODYxLTAwAi0wMAoARgAAA428HhUZWjFJpUSRJeFqnBwHAHQq8eP3dM1JkMChdMfyLSgAAAIBCQAAAHQq8eP3dM1JkMChdMfyLSgAAABaRuP3AAAA"" ChangeKey="CQAAABYAAAB0KvHj93TNSZDAoXTH8i0oAABaYEei" />
</t:MeetingRequest>
</t:Delete>
</m:Changes>
</m:SyncFolderItemsResponseMessage>
</m:ResponseMessages>
</m:SyncFolderItemsResponse>
</s:Body>
</s:Envelope>
其中IncludesLastItemInRange节点是告知是否已经返回了所有的变更信息,如果没有,则需要再用新的SyncState再请求多一次,直到IncludesLastFolderInRange节点为true。
使用这两个同步的接口,就可以方便的获取到服务器变更的内容。 理论上,同步folder中的邮件列表,使用SyncFolderItems这个命令就足够了,在将SyncState更新到最新状态时,客户端已经同步到了folder中所有的邮件的id,之后便可以拉取所有的邮件的摘要了。但是在移动客户端中,下载所有的邮件并不是非常理智的行为,非常耗费流量和存储空间。因此在移动客户端中,初始化folder时对邮件的同步数目需要进行限制。为了解决这个问题,在移动客户端中,对邮件里列表的同步分为一下三个操作:
初始化阶段:获取最新的SyncState,对这个过程中返回的所有邮件id截取最新的n个id进行邮件下载,存储。下拉更新阶段:使用当前存储的SyncState拉取到所有变化的邮件id,全部进行下载存储。加载更多阶段:用当前存储的最旧邮件的发送时间time1,使用findItem命令搜索不晚于time1时间发送的最近n封邮件邮件id,进行下载存储。
结合SyncFolderItems和findItem两个请求,就可以不需要在初始化邮件列表时中同步所有邮件,但是又可以支持加载旧邮件的需求。
转载请注明原文地址: https://ju.6miu.com/read-38430.html