使用XML来传递消息会给您的应用程序带来许多好处:通过它您可以利用大量的API、跨平台支持、以及用来描述和操纵XML(例如Xquery,XSLT,XPath和XML Schema)的通用工具。你不想关心的许多细节问题也可以由XML来处理——比如行结束、字符编码、结构化数据和分界——这使您只需将精力集中于您的应用程序。由于上述所有的原因,能使用XML是非常好的。
尽管用XML来传递消息存在巨大优势,但是其缺点是性能问题:由于XML的设计方式,有些数据类型不能很好的与XML集成。由于XML是基于文本的形式,最显著的是二进制数据(即不能被表示为Unicode字符集的任何东西)。
开发人员要做什么呢?
使用URL引用
最容易的解决办法就是在你的XML中不包括这样的数据,而是像HTML中使用URL那样在Web上引用它。例如,如果你的应用程序的消息需要包含一个人的JPEG图片,那么带有嵌入式链接的XML可能如下所示:
<?xml version='1.0' ?>
<soap:Envelope xmlns:soap="...">
<soap:Body>
<Person name="bob">
<Picture>http://www.example.com/people/bob.jpg</Picture>
</Person>
</soap:Body>
</soap:Envelope> |
如果数据是长时间稳定且对消息的接收者而言是可用的,这种方式能够发挥很好的作用。然而,如果数据是短暂的,或者数据的接收者没有连接到Web,这就不是一个好的解决办法。为了处理这些情况,数据必须随着消息进行传送。
使用编码
把二进制的数据放入一条基于XML的消息的最简单的方法,就是使用类似Base64的方式对其进行编码,把它转变成对XML 安全的一串字符(以及7位的MIME传输,XML最初就是针对它设计的)。使用Base64编码,我们的图片XML 可能如下所示:
<?xml version='1.0' ?>
<soap:Envelope xmlns:soap="...">
<soap:Body>
<Person name="bob">
<Picture>Li4uYmluYXJ5IGpwZWcgaW1hZ2UuLi4=</Picture>
</Person>
</soap:Body>
</soap:Envelope> |
XML Schema定义了一种base64Binary类型,这是一种足够通用的方法,使您能够照此识别已编码的二进制内容(它也定义一种hexBinary类型,这是一个可选的编码模式,但还不是很流行)。
这种编码的不利方面是它的低效率;因为数据的二进位形式使用有限范围的字符集来表示丰富的数据流,它通常比base64形式更简洁。通常,对于给定的数据流,base64编码会引入33%的冗余尺寸,从而使XML消息更大。
另外,对二进制数据进行编码和解码会造成相当大的处理开销,这反过来会影响使用它的应用程序的可扩展性和性能。
使用带附件的SOAP消息
这些问题促成了带附件的SOAP消息(SOAP Messages with Attachments (SwA))的开发。带附件的SOAP消息是一种特定于Web Services的技术,它使用MIME Multipart/Related数据包来随XML消息发送二进制数据和其它附件,从而避免了编码的开销。用于我们的图片的一个简化的SwA消息可能如下所示:
Content-Type: Multipart/Related; boundary=MIME_boundary; type=text/xml
--MIME_boundary
Content-Type: text/xml; charset=UTF-8
Content-Transfer-Encoding: 8bit
<?xml version='1.0' ?>
<soap:Envelope xmlns:soap="...">
<soap:Body>
<Person name="bob">
<Picture>cid:bob@pictures.example.com</Picture>
</Person>
</soap:Body>
</soap:Envelope>
--MIME_boundary
Content-Type: image/jpeg
Content-Transfer-Encoding: binary
Content-ID: <bob@pictures.example.com>
...binary JPEG image...
--MIME_boundary-- |
我们可以看到,图像数据在一个MIME附件中。它是从带有一个cid(URL)的SOAP消息而被引用的,这个URI使用Content-ID MIME头的值来找到正确的附件。
这样避免了编码的开销和冗余,但是也带来了一些新的问题。XML和Web Services的大部分价值在于使用generic XML工具来处理内容的能力——像XPat、XQuery、XSLT、XML 加密和数字签名以及XML schema一样。这些工具不处理非XML的内容;如果您想要对这些内容进行查询、转换、加密、签名或者描述,您就需要使用一种不同的机制,甚至建立一种新的机制。
此外,由于SwA还存在相当多的互操作性问题,以致于WS-I一直致力于研究(在写作本文时)适合它们的特定的互操作性配置文件。
实际上,带有附件的SOAP消息引进了一种新的消息数据模型,因此,它不再是基于XML的消息传递了。在2003年的早期,BEA公司和Microsoft公司就开始关注并撰写关于这个问题的白皮书,并且开始探索其他可能的选择。
MTOM和XOP的引入
在找出与SwA相关的那些问题之后,我们开始研究制订一个具体的解决方案。这项工作从Proposed Addendum to SOAP Messages with Attachments(PASWA)开始,并且W3C 的XML协议组(该组提出了SOAP 1.2)一直将它作为Message Transmission Optimization Mechanism(MTOM)和XML-binary Optimized Packaging(XOP)的规范加以研究。
上述内容背后的思想很简单。 XOP是XML的可选序列化方法,使您能够将任何XML文档表示为XOP数据包。在XOP数据包里,任何被命名为base64字符串的事物都作为附件进行编码,其方法与SwA的方法非常相似。不过,数据和附件之间的链接不同:它不是依靠应用程序进行处理,而是由该格式自行处理。
例如,当我们图片文档在作为一个XOP数据包而被序列化时,可能如下所示:
Content-Type: Multipart/Related; boundary=MIME_boundary; type=text/xml
--MIME_boundary
Content-Type: text/xml; charset=UTF-8
Content-Transfer-Encoding: 8bit
<?xml version='1.0' ?>
<soap:Envelope xmlns:soap="..."
xmlns:xbinc="...">
<soap:Body>
<Person name="bob">
<Picture><xbinc:Include
href="cid:bob@pictures.example.com"/></Picture>
</Person>
</soap:Body>
</soap:Envelope>
--MIME_boundary
Content-Type: image/jpeg
Content-Transfer-Encoding: binary
Content-ID: <bob@pictures.example.com>
...binary JPEG image...
--MIME_boundary-- |
从XML观点来看,该文档与上面的base64版本同构;也就是说,其中任何一种都可以编码为另外一种,而不会造成信息的丢失。与SwA不同,XOP使用xbinc:Include元素显式地将内容与正确的附件关联起来,并避免了SwA中存在的许多歧义性。它也保持XML 消息的数据模型;因为它只是XML的一种可选编码,实际上,可以将附件中的二进制内容视为XML自身中的base64编码的数据。
XOP是一个通用的机制;我们能用它来序列化任何种类的XML。在SOAP中,MTOM使XOP串行化和反串行化成为可能,这是HTTP绑定的扩展。随着其他绑定被定义出来,它们也将包含XOP支持。
从API角度来看,XOP隐含着一些有趣的内容。如果一个XML栈能够理解XOP编码,那么您的应用程序就根本不需要改变;例如,当它需要访问图片时,它仍然能够将所获得内容的字符值看作base64编码字符串。如果XOP正在使用中,那么该实现可以即刻自动将其编码。
这就能够将XOP透明地逐步部署到应用程序中,但是并不能产生期望的性能收益。为了产生期望的性能收益,应用程序需要通过使栈显式地为它执行base64编码和解码来访问二进制内容的值空间,而不是词法空间。
实际上,这相当容易做到。为了兼容XOP,需要用一种简单方法来扩展XML API,从而访问值空间。例如,SAX定义了characters()方法来处理字符数据,包括我们的图片元素。通过定义一种新方法——例如binary() 方法,自动地对base64编码的内容进行合适的解码, 或者当xbinc:Include 存在时,取消对附件的引用。应用程序可以更容易地实现由XOP提供的收益。
当我们考虑类型感知API,(像XML beans)时,事情变得更有意思了。因为它提供了访问XML 内容的词法空间和值空间的方法,所以有可能在类似XOP的类型感知编码中进行无形的分层。
建议
在写作本文时,W3C仍然在开发XOP和MTOM,但是它们进展迅速,并且拥有来自Web服务行业的各个巨头的充分支持。因此,我们预计XOP和MTOM将成为主流的Web Services附件机制。
另外,XML API——包括DOM,SAX,StAX和XML beans——将需要进行修改,以实现由XOP带来的好处。由于XOP得到Web Services领域的一致认同及其简洁性,我们期望这种修改会迅速实现。
同时,最好的选择是使用一个URI引用和编码;对于某些应用程序类型而言,URI引用总是有用的,并且编码与XOP的透明兼容性意味着,当XOP得到更广泛的采用时,很容易进行升级。