Web Service 附件技术的发展及演变

Web Service 通常将业务数据封装在 SOAP 主体或者 SOAP 消息附件中进行传输,这些附件往往采用 Base64 编码二进制方式进行封装,这将大大增加待传输的数据量,消耗比较长的编码时间和传输时间。随着 SOA 以及 Web Service 技术的广泛采用,由于网络带宽,延时的影响以及内存大小的限制,越来越多的应用对 Web Service 附件传输方式以及传输效率提出了更高的要求。

引言

本文对 Web Service 附件技术及其相关开发工具进行了总结,详细介绍了 Web Service 附件技术的发展及其演变。近些年,先后有 SwA, DIME, WS-Attachments, PASwA, XOP, MTOM 等规范产生,经过不断的改进,SOAP 消息附件封装方法已经有了比较满意的解决方案,附件传输和处理效率上得到了很大提高,其打包和传输方式也逐渐具有统一的处理方法。


Web Service 数据交换协议

Web Service 使用 SOAP 作为其标准的数据交换协议。SOAP 是一个基于 XML 的轻量级协议,用于在无中心、分布式环境中交换结构化的数据,该协议完全独立于具体的系统平台、软件架构和编程语言,提供了一种开放和统一的方式支持应用间的集成和互操作。

SOAP 的设计目标是简单性和扩展性,有助于大量异构程序和平台之间的互操作性,从而使存在的应用程序能够被广泛的用户访问。目前,SOAP 已经成为开放性互联网络应用中标准的数据交换技术。2000 年 W3C 推出了 SOAP1.1 版本,最新的 SOAP1.2 在 2007 年 4 月推出,并成为 W3C 的推荐规范。

SOAP 只是为上层应用提供一个数据的载体,数据的具体语义由上层应用定义。SOAP 报文最外层元素为 Envelope,即 SOAP 信封。Envelope 之下有两个子元素:Header 元素和 Body 元素。其中 Body 元素是 SOAP 报文的主要数据载体,该元素是必需的。用于存放待交换的信息,具体表示为 Body 的子元素;Body 的每个直接子元素称为 Body Block,用于存放具体应用中在逻辑上相关的一组数据;Header 元素是可选的,主要用于扩展机制,Header 的直接子元素称为 Header Block,每个 Header Block 的扩展语义由基于 SOAP 的上层应用来定义,常用的扩展包括安全、事务、消息相关性等。

SOAP 故障 (Fault) 报文是一种特殊的 SOAP 报文,用于在发生故障的场景中运载错误信息。在 SOAP 故障报文中,Body 有且仅有一个名为 Fault 的直接子元素,用于存放和具体故障有关的详细错误信息,包括故障代码、故障原因、发生故障的 SOAP 结点等。图 1 为 SOAP 数据报文和 SOAP Fault 报文示意图。

图 1. SOAP 数据报文和 SOAP Fault 报文

在 Web Service 的实现中,经常需要在 SOAP 报文中携带各种类型的附件 ( 如图像、文档等 ) 一起传输。例如,在典型的电子商务应用中,客户向商家询问某种商品的详细信息,商家向客户发回 SOAP 格式的回复消息,其中包含有商品的详细说明,商品的图片等供客户参考。这些附件可能是文本文件,XML 片段,二进制文件等等。然而,SOAP 是一种基于 XML 的文本协议,只能使用可见字符组成的文本来表示数据,无法在报文中直接包含其他格式的附件。因此,如何将 SOAP 报文同其他格式的附件组织在一起进行传输便成为一个需要解决的重要问题。

为了对 SOAP 及其他 Web Service 标准进行支持,Java 社区进程组织 (JCP: Java Community Process) 提供并实现了 Java 方面的 Web 服务的原始标准 JAX-RPC1.x (JavaTM APIs for XML based RPC) 和 JAX-WS (JavaTM API for XML-Based Web Services 2.0)。JAX-RPC 最早版本是 JAX-RPC1.0,进过一段时间使用便更新到 JAX-RPC1.1,在 J2EE1.4 中包含 JAX-RPC1.1。JAX-RPC1.1 使用约 1 年后 JCP 再次对其进行更新,考虑到 Web 服务中不单有 RPC Web 服务,还有面向消息的 Web 服务,因而将其更名为更合理的 JAX-WS。目前 JAX-WS2.0 仍在进行当中。JAX-RPC1.1 提供对 SOAP1.1 的支持,JAX-WS2.0 对 SOAP1.1 和 SOAP1.2 进行支持。


Base64 编码的二进制 SOAP 附件

为了简单和通用性,XML 被设计成了以文本的格式来表示数据。使用 SOAP 进行传递的数据首先被序列化,也就是将数据转换成字符串在 XML 文档中传送。在目的地,字符串再被反序列化,即再被转换成表示原来的值的数据类型。把二进制数据放入 SOAP 报文的最简单的方法,就是使用 Base64 编码的方式对其进行编码,以实现数据的序列化和反序列化。

Base64 是一种很常见的编码规范,其作用是将二进制序列转换为可读的 ASCII 字符序列,常用在需用通过文本协议传输二进制数据的情况下,例如 HTTP 和 SMTP 协议。Base64 编码基本原理是把每三个 8bit 的字节转换为四个 6bit 的字节,然后把 6bit 再添两位高位 0,组成四个 8bit 的字节,不满四个字节的以 '=' 填充。因为 Base64 将输入的数据编码成只含有 {'A'-'Z', 'a'-'z', '0'-'9', '+', '/'} 这 64 个字符的串,所以称之为 Base64 编码。可以看出,转换后的字符串理论上将要比原来的长 1/3。

在 W3C 的 XML Schema Part 2: Datatypes 规范中,定义了 base64Binary 类型,SOAP 报文中使用 Base64 编码的二进制内容可以定义为该类型。一个使用 Base64 编码的图片数据在 SOAP 报文中的结构如清单 1 所示:

清单 1. 一个使用 Base64 对数据进行编码的 SOAP 报文
<?xml version='1.0' ?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
 <soap:Body>
 <Car name="myCar">
 <BNZE xsi:type="xsi:base64Binary">L3EWw43eku34EEli34wejlE72=</BNZE>
 </Car>
 </soap:Body>
</soap:Envelope>

MIME 与 SOAP Messages with Attachments

尽管使用 Base64 编码能够将二进制数据放入 SOAP 报文中进行传输,然而,其效率非常低下。根据前面对 Base64 编码原理的分析,采用 Base64 编码将会引入 33% 的冗余尺寸,从而使 SOAP 消息变大;另外,对二进制数据进行编码和解码将造成较大的时间开销,严重影响应用程序的性能。鉴于这些问题,2000 年 12 月,W3C 组织推出了 SOAP 附件标准:SOAP Messages with Attachments (SwA) 规范,将 SOAP 附件置于 SOAP 主体之外,基于 MIME 技术实现了 SOAP 报文同 SOAP 附件的封装。

MIME (Multipurpose Internet Mail Extensions) 多用途互联网邮件扩展,是当前广泛应用的一种电子邮件技术规范,基本内容定义于 RFC 2045-2049。MIME 出现之前,邮件中只能发送 ASCII 码文本信息,如果要发送二进制文件,如声音和视频等,难以实现。MIME 使得在邮件中支持多种不同编码文件成为可能。尽管 MIME 一开始用于邮件传输中,现在 MIME 已经成为 HTTP 协议标准的一部分。

MIME 消息由消息头和消息体两大部分组成,邮件头与邮件体之间以空行进行分隔。邮件头包含了发件人地址 (From)、收件人地址 (To)、主题 (Subject)、MIME 版本 (MIME-Version)、内容的类型 (Content-Type),内容的传输编码方式 (Content-Transfer-Encoding) 等信息,每条信息称为一个域。邮件体包含邮件的内容,类型由邮件头的“Content-Type”域指明,分为简单类型和 Multipart 类型。简单类型如 text/plain, text/html 等,Multipart 类型表明将邮件体分为多个段,每段又分为段头和段体,也以空行分隔。常见的 Multipart 类型有三种:Multipart/Mixed, Multipart/Related 和 Multipart/Alternative。如果邮件中要添加附件,而且附件之间有相互关联关系,则使用 Multipart/Related。

SOAP 附件标准 SwA 只针对 SOAP1.1 版本,其 MIME 类型为 Multipart/Related,表示文档的多个部分是相关的,Multipart/Related 报头的 type 参数值为”text/xml”。SOAP1.1 消息主体位于 Multipart/Related 结构的第一段,其 Content-Type 的值也为”text/xml”。其余的 MIME 段为 SOAP 附件,附件可以是任意类型数据,每个附件 MIME 段由段头的 Content-ID 或者 Content-Location 唯一标识,比较常用的是 Content-ID。

图 2 为 SwA 规范下的带附件 SOAP 报文结构图。图中 SOAP 消息由 MIME 头,一个封装主体 SOAP1.1 消息的 MIME 段和一个或多个封装 SOAP 附件的 MIME 段三部分组成。其中每部分以 MIME 边界分隔,Context-Type 用于指定 MIME 段的数据的类型、Content Transfer-encoding 用于指定用于 MIME 段的编码方式、Content-ID 或者 Content-Location 用于作为该 MIME 部件的标识符。

图 2. SwA 规范下带有附件的 SOAP 报文

 

清单 2 是一个基于 SwA 的 SOAP 报文示例。例子中的图像数据在一个 MIME 结构中,通过属性”href”被引用的,href 的值为一个 URI,URI 使用 MIME 头的 Content-ID 值来找到附件。

清单 2. 一个基于 SwA 的 SOAP 报文
POST /test HTTP/1.0
Content-Type: Multipart/Related; boundary=MIME_boundary; type=text/xml
Content-Length: XXXX
SOAPAction: http://www.soapattach.com/test

--MIME_boundary
Content-Type: text/xml; charset=UTF-8
Content-Transfer-Encoding: 8bit

<?xml version='1.0'?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
 <soap:Body>
 <Car name="myCar">
 <Picture href = “cid:benz@pictures.soapattach.com”/>
 </Car>
 </soap:Body>
</soap:Envelope>

--MIME_boundary
Content-Type: image/jpeg
Content-Transfer-Encoding: binary
Content-ID: <benz@pictures.soapattach.com>

...binary JPEG image...

--MIME_boundary--

SwA 避免了编码的开销和冗余,但是也带来了一些新的问题。首先,SwA 使用字符串作为 MIME 结构的定界符,为了解析出 MIME 结构,必须遍历所有数据,当数据量较大时,效率非常低下,当 MIME 结构中出现和定界字符串相同内容的情况时,处理起来更复杂;其次,通用的 XML 技术,如 XPath、XQuery、XSLT 以及 XML schema 等,对于 XML 文件中包含的二进制内容无法处理,因而也无法对符合 SwA 的 SOAP 报文使用各种通用的 XML 技术进行处理。尽管程序知道附件数据的存在,但是文档自身并不知道,另外,不同的 SOAP 报文处理器,以及 SOAP 消息和 WSDL 之间存在大量的互操作性问题。在 Web 服务互操作性组织 WS-I 的官方网站上可以找到其所总结的各种 Web Service 互操作性问题的详细信息。

在 SwA 的具体实现中,涉及到三种主要的 API:SAAJ (SOAP with Attachments API for Java), JAXM (Java API for XML messaging), JAX-RPC。这三种 API 都是 JCP 所制定的 Web Service 的 Java 实现标准。SAAJ 是实现 SwA 规范的 API,是从 JAXM 1.1 中分离出来的。SAAJ 包含许多类和接口,用来定义 SOAP 元素 (Envelope, Body, Header, Fault 等 ),XML 名称空间,以及 MIME 附件等。通过 SAAJ 提供的 API 可以生成带 MIME 附件的 SOAP 消息。J2EE1.4 包含了 SAAJ1.2,该版本支持 SOAP1.1,J2EE1.5 包含了最新的 SAAJ1.3。而 JAXM 是面向文档的用于将 SOAP 消息以 XML 格式进行异步传送的 API。JAXM 客户端使用 SAAJ 来构造和解析 SOAP 消息。JAX-RPC 依赖于 SAAJ,提供了 RPC 方式 Web 服务实现,定义了三种客户端编程模型:Generated Stub、Dynamic Proxy 和 Dynamic Invocation Interface。


DIME 与 WS-Attachments

为了解决 SwA 的效率低下问题,2002 年 7 月,IBM 和微软向 IETF 提交了直接因特网消息封装提议 (DIME: Direct Internet Message Encapsulation),以及相应的 WS-Attachments 规范,使用 DIME 和 WS-Attachments 对 SOAP 消息附件进行封装。

DIME 是一个轻量级二进制消息格式,能够将任意格式数据的多个记录序依次序列化为流,使用有效的二进制标头进行说明。

DIME 记录标头包含 DIME 版本、数据的类型信息、唯一标识每个记录的 ID、数据长度信息以及可选信息等。DIME 消息的第一个记录在标头中设置了消息开始标志 MB,最后一个记录设置了消息结束标志 ME。MB 和 ME 标志均是一个 1 位字段,当被置位时,分别表明 DIME 消息的开始和结束。对于较大的记录或最初不知道数据大小的记录,DIME 定义了“记录区块”,使用记录区块将单个记录分解成多个块。记录区块在标头中设置了区块标志 CF,表明该数据是分块记录的一部分,并且其后包含更多的数据。

数据字段携带 DIME 用户应用程序的有效负载。数据字段内携带的数据的内部结构对 DIME 是不透明的。数据字段的长度必须是 4 个 8bit 数据的倍数。如果有效负载的长度不是 4 个 8bit 数据的倍数,那么用全零 8bit 数据填充。填充部分并不算在数据长度字段中,并且绝不可以用超过 3 个 8bit 数据填充数据字段。图 3 为 DIME 数据记录格式

图 3. DIME 数据记录格式

DIME 根据某个记录的开始位置,可以轻松地定位到下一个记录的位置,只需将标头固定区域的长度与可选数据、ID、类型和数据部分的长度相加。这种以高效方式确定记录长度对于在流的记录之间快速移动十分重要。

DIME 本身只是一种用来对任意格式的数据记录集合进行打包的机制。它对于记录有效负载的内容、ID 字段中包含的内容或者如何将 SOAP 消息封装到 DIME 消息中等没有任何要求。DIME 的记录内容没有任何限制,其有效负载甚至可以包含其他 DIME 消息,只需将该记录的类型设置为“application/dime”。

WS-Attachments 定义了如何使用 DIME 数据包发送包含附件的 SOAP 消息,标识了 DIME 消息中哪些是 SOAP 消息,哪些是附件。对于包含附件的 SOAP 消息,将主要消息称为“主 SOAP 消息部分”,将附加的部分称为“从属部分”。WS-Attachments 要求主 SOAP 消息部分必须包含在 DIME 消息的第一个记录中,主 SOAP 消息部分通过使用 href 属性引用附件,其值为 HTTP URL。此外,WS-Attachments 还说明了如何使用 DIME 记录标头的 ID 字段引用特定的 DIME 记录。

清单 3 是一个基于 WS-Attachments 的 SOAP 报文,其中 DIME 消息的从属部分的 ID 为 uuid:6FF57555-8750-4555-8237-95ELIWEK87B4F,引用了此类附件的主 SOAP 消息部分的代码如下所示:

清单 3. 基于 WS-Attachments 规范的 SOAP 报文
<soap:Envelope 
 xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" 
 <soap:Body> 
 <attach:responseMesssage xmlns:attach="http://example.net /attachment">
 <attach:message 
 href="uuid: 6FF57555-8750-4555-8237-95ELIWEK87B4F"/> 
 </attach:responseMessage>
 </soap:Body> 
</soap:Envelope>

该消息正文中的 message 元素的 href 属性用来指定 DIME 记录的 ID。DIME 记录中的数据可能是此消息所响应的另一个 SOAP 消息,此时 DIME 消息的接收方可以从 DIME 消息指定的从属部分中找到该消息。WS-Attachments 不但可以从主 SOAP 消息部分中引用 DIME 消息的从属部分,也可以从从属部分中进行类似引用,这样两个从属部分就可以相互引用,甚至一个从属部分还可以引用主 SOAP 消息部分。

WS-Attachments 还说明了如何在 HTTP 请求中发送复合 SOAP 消息。这种情况下,HTTP 的 Content-Type 标头必须设为“application/dime”,HTTP 请求的正文为 DIME 消息而不是 SOAP 消息。

尽管 DIME 解决了 SwA 中遍历定界符导致的效率低下问题, DIME 强迫开发者从 MIME 完全转向 DIME,最后导致 DIME 和 WS-Attachments 并没有得到广泛应用。


PASwA, XOP 和 MTOM

为了解决 SwA 导致的互操作性问题,2003 年 4 月 Microsoft, BEA, Canon, SAP 和 Tibco 等公司提出了规范 Proposed Infoset Addendum to SOAP Messages with Attachments (PASwA)。PASwA 基于 SwA 规范,是对 SwA 规范的补充。

PASwA 一个重要目标是使 XML Infoset 具有一个统一的逻辑视图,而不需要对由于 XML 中包含二进制数据,SwA 和 WSDL 之间的互操作性等问题而另外处理。XML Infoset 定义了一种抽象的方式,把 XML 文档描述为一系列信息项,为需要引用 XML 文档中的信息的规范提供了一致的定义。

PASwA 主要增加了如下内容:

  • xmime:mediaType 属性:用于指明 XML 文件中 base64 编码部分的媒体类型,例如 xmime:mediaType 的值可以为 image/png,audio/mpeg,application/pkcs7-signature 等,这些值在 RFC 2045 和 RFC 2046 指定
  • xmime:Binary 类型:基于 xs:base64Binary 的复合类型,xmime:mediaType 为其可选属性
  • Swa:Accept 属性:用于申明其所支持的媒体类型,主要用于 WSDL 中
  • 带有 herf 属性的 xbinc:Include 元素:在 SOAP 消息中链接到相关的附件数据
  • 在 SOAP 消息头中增加了 xbinc:DoInclude 和 swa:Representation 块:xbinc:DoInclude 用于表示 SOAP 报文中包含 xbinc:Include 元素,SOAP 消息处理器应该特殊处理;swa:Representation 表示允许 SOAP 节点发送缓存的 Web 资源

尽管 PASwA 并没有被 W3C 所采纳,然而,PASwA 直接导致了 W3C 的 XML 二进制优化打包 (XOP: XML-binary Optimized Packaging) 和 SOAP 消息传输优化机制 (MTOM: Message Transmission Optimization Mechanism) 规范的产生。

XOP 使用 MIME 将原始二进制数据引入到 XML 1.0 文档中。XOP 是 XML 的可选序列化方法,在 XOP 数据包里,被命名为 base64 字符串的事物都可以作为其附件,方法与 SwA 类似。所不同的是:数据和附件之间的链接不是依靠应用程序进行处理,而是由该格式自行处理。XOP 使用 xop:Include 元素显式地将内容与附件关联起来,并避免了 SwA 中存在的歧义性。

在 XOP 规范中主要有如下基本元素:Original XML Infoset,Optimized Content,XOP Infoset,XOP Document,XOP Package 和 Reconstituted XML Infoset。其定义如下:

  • Original XML Infoset 是需要被优化的原始 XML Infoset
  • Optimized Content 是原始 XML Infoset 中需要被优化的内容
  • XOP Infoset 是使用 xop:Include 元素替换掉原来 XML Infoset 中的相应信息得到的新的 XML Infoset
  • XOP Document 是符合 W3C recommendation 规范序列化后的 XOP Infoset
  • XOP Package 是 XOP Document 和 Optimized Content 的打包。XOP Package 是原始 XML Infoset 的一种可选的序列化方式
  • Reconstituted XML Infoset 是使用 XOP 包组成的 XML Infoset

一个完整的 XOP 消息包包括以下 3 个部分:MIME 头,主体 SOAP 消息部分和附件部分。其中,MIME 头的类型,即 Content-Type 的值总是为 Multipart/Related,其 type 参数总是等于主体 SOAP 消息的 Content-Type 的值,也就是 application/xop+xml;主体 SOAP 消息部分,用于存储 XOP Infoset 格式的 SOAP Envelop;附件部分,用于存储二进制或者非二进制附件数据。

清单 4 为原始 XML Infoset,其中 attach:Car 元素为原始 XML Infoset 中需要被优化的内容。清单 5 为序列化后的 XOP 包,该 XOP 包中只含有一个附件数据。

清单 4. 原始 XML Infoset
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"
 xmlns:xmlmime="http://www.w3.org/2004/06/xmlmime">
 <soap:Body>
 <attach:Car name="Eric" xmlns:attach="http://example.cn/attachment">
 <attach:Picture xmlmime:content-type='image/jpeg'>WE72WEWTi2VuYJY=
 </attach:Picture>
 </attach:Car>
 </soap:Body>
</soap:Envelope>
清单 5. 序列化后的 XOP Package
MIME-Version: 1.0
Content-Type: Multipart/Related; boundary=MIME_boundary;
type= application/xop+xml;
start="<paper@example.cn>";
start-info="application/xop+xml"

--MIME_boundary
Content-Type: application/xop+xml; charset=UTF-8
Content-Transfer-Encoding: 8bit
Content-ID: <paper@example.cn>

<?xml version='1.0'?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"
 xmlns:xmlmime="http://www.w3.org/2004/06/xmlmime">
 <soap:Body>
 <attach:Car name="Eric" xmlns:attach="http://example.cn/attachment">
 <attach:Picture xmlmime:content-type='image/jpeg'>
 <xop:Include xmlns:xop='http://www.w3.org/2004/08/xop/include' 
 href="cid:Eric@pictures.example.com"/>
 </attach:Picture>
 </attach:Car>
 </soap:Body>
</soap:Envelope>

--MIME_boundary
Content-Type: image/jpeg
Content-Transfer-Encoding: binary
Content-ID: <Eric@pictures.example.com>

...binary JPEG image...

--MIME_boundary--

在 SOAP 消息构造和传输中使用 XOP 的过程称为 MTOM。MTOM 的目的在于优化 base64 编码数据的传输。只有具有 xs:base64Binary 标准格式的字符组成的节点才可以被优化。使用 MTOM,SOAP 消息包以 XOP 消息包的格式传输。

此外,为了解决 SwA 导致的互操作性问题,与 PASwA 和 MTOM 同时进行的,还有 WS-I 的附件概要规范。2004 年 8 月 24 日,WS-I 推出了附件概要 AP1.0 (Attachment Profile Version 1.0) 规范,用以解决 SOAP 消息和基于附件的 Web 服务之间的互操作性问题,最新版为 2006 年 4 月 20 日发布的 AP1.0 第二版。AP1.0 和 WS-I 的另一规范,简单 SOAP 绑定概要 SSBP1.0 (Simple SOAP Binding Profile 1.0),构成了 WS-I 的基本概要 BP1.1(Basic Profile Version 1.1) 的补充规范。由于 AP1.0 和 PASwA 以及 MTOM 的冲突,很多开发者并没有采用 AP1.0,而是直接转向 MTOM。

在 JAX-RPC1.1 中,提供了对 BP1.0 的支持,JAX-WS2.0 已经提供或者即将提供对 BP1.1, AP1.0, SSBP1.0, XOP 以及 MTOM 的支持。

目前,IBM WebSphere 产品已经提供了对 MTOM 和 XOP 的支持,在其最新发布 WebSphere Application Server Feature Pack for Web Services 中可以找到相应实现,用户只需安装 WAS 6.1 feature pack for Web Services,关于 IBM 对 MTOM 更详细的实现信息可见参考资料中的 WAS6.1 专门针对 Web Service 包的介绍。


总结

随着 Web Service 技术的广泛采用,对其附件技术的要求也越来越高,先后出现了 SwA, DIME, WS-Attachments, AP1.0, PASwA, XOP, MTOM 等规范。其中,DIME, WS-Attachments 已经基本被淘汰了;目前使用比较广泛的是 SwA 和 AP1.0,其缺点是存在大量的互操作性问题和效率问题;XOP 和 MTOM 提供了一种通用和高效的机制,其相应规范仍在完善中,随着其推广应用相信今后必将被广泛采用。


参考资料

 

完。

 

posted @ 2014-12-22 11:56  liyou  阅读(684)  评论(0编辑  收藏  举报