经典技术文章转载:SOAP编码讨论-老徐的博客-博客园
摘要:本文阐述了 SOAP 历史所遗留下来的 SOAP 编码(又称“Section 5 编码”)为什么在 Web 服务的未来发展中没有立足之地。(11 页打印页)
本页内容
简介
SOAP 的发展历程和 Web 服务
问题的核心
具体示例
解决编码问题
未来
简介几大洲几大洋
SOAP 是基本 Web 服务协议栈的基石。 SOAP 规范正式确认将 XML 消息作为一种通信方法来使用。 它定义了一种扩展性模型、一种表示协议和应用程序错误的方法、通过 HTTP 发送消息的多个规则以及将 RPC 调用映射到 SOAP 消息的多个原则。 使用标准的方法来进行这些操作是很有益的。 否则,每个想要通过 HTTP 发送 XML 消息的开发人员将不得不针对这些问题创建自己的特定解决方案,从而使互操作性很难以实现。 虽然 SOAP 规范的大多数内容对我们来说都是好的,但是其中有一项却不然: SOAP 编码。 SOAP 编码(根据该编码方法的定义在 SOAP 1.1 规范中所处的部分,有时被称为“Section 5 编码”)是 SOAP 历史所遗留的一个问题,它在 Web 服务的未来中没有立足之地。 本文将解释其中的原因,让我们首先回顾一下历史。
返回页首
SOAP 的发展历程和 Web 服务
在编写第一个 SOAP 规范时,Web 服务背后的各种概念尚处在萌芽阶段。 人们计划利用 SOAP 将分布式对象技术(例如,DCOM、CORBA 和 RMI)与本机的 Internet 技术(例如,XML 和 HTTP)更好地集成起来。 目标是要建立一种管道,以便创建并使用基于 XM
L 的消息,而不使用由不同的技术(分别是 NDR、CDR 和 JRMP)支持的各种二进制消息格式。
为了让分布式应用程序中的客户端和服务器创建并使用消息,它们需要知道这些消息应该是什么样子。 大多数分布式对象系统依赖于编译的 proxy/stub/skeleton 和元数据的二进制表示形式(例如,COM 类型库、CORBA 接口库或 Java .class 文件)的组合来提供这些信息。 SOAP 没有改变这一点。 SOAP 规范的作者们假定应用程序开发人员将确保客户端和服务器已经具有正确处理 SOAP 消息所需的任何信息。
然而,SOAP 作者们认识到如果自己不打算定义一种通用方法来对消息进行描述,那么至少也应就如何将通用的面向对象的编程结构映射到 XML 提供一些指导。 他们不能使用 XML 架构 (XSD) 来解决这个问题,因为那时 XSD 还远未完成。 于是,他们基于非类型化结构的图定义了一种数据模型。 然后,他们编写了 SOAP 编码规则,其中解释了如何将 SOAP 数据模型的实例序列化为 SOAP 消息。 而将具体技术映射到 SOAP 数据模型的工作则留给实现者来完成。
随着 SOAP 日渐获得业界的重视,一个新的要求出现了。 开发人员想要下载有关 SOAP
服务器的消息格式的说明,以便能够创建客户端来与其对话。 因为想要提供这种说明的服务器不能对用于创建客户端的技术进行任何假设,所以通过现有的元数据格式(例如,类型库)来公开消息说明的做法是行不通的。 此问题的解决方案就是使用一种跟 SOAP 自身一样可移植的通用元数据格式,也就是 WSDL。 WSDL 利用 portType 来说明某项 Web 服务所支持的行为。 PortType 是操作的集合。 操作是以消息的形式定义的。 消息是以 XML 架构的形式定义的。 如今,在大多数人看来,SOAP 和 WSDL 相当紧密地联系在一起;它们连同 UDDI 一起确立了基本的 Web 服务构造块。
返回页首
问题的核心
万维网创始人万惠WSDL 的作者认识到 XSD 在说明 SOAP 消息方面扮演了重要角,因此采用了 XSD(但他们也允许使用其他替代方案)。 他们还意识到有些工具包已经实现了 SOAP 编码方案,所以觉得也有必要采用 SOAP 编码。 他们提出的解决方案就是根据 XML 架构结构来定义消息,然后,如果需要的话,允许利用绑定向这些消息应用 SOAP 编码。
绑定定义用户在调用由某个 portType 定义的操作时需要知道的一些具体细节。 (这并不是一种新概念。 例如,COM 类就经常通过 vtable 绑定和 IDispatch 绑定来公开其方法。 类似地,通常也可以通过静态 stub 或动态调用接口来提供 CORBA 类的方法。) 当创建可将某个 portType 的操作映射到通过 HTTP 发送的 SOAP 消息的 WSDL 绑定时,您必须指明 SOAP 消息中所包含的该 portType 的操作所使用的架构结构的实例是文字的还是编码的。 如果您选择“文字的”,就意味着 WSDL 定义所引用的 XML 架构结构是 SOAP 消息主体中将显示的内容的具体规范。 如果您选择“编码形式”,则意味着 WSDL 定义所引用的 XML 架构结构是 SOAP 消息正文中将显示的内容的抽象规范;通过应用由 SOAP 编码定义的规则可将这些抽象规范变为具体规范。 (WSDL 规范也允许其他编码方案,但这些替代方案即使得到过使用,那也是很罕见的。)
这就给我们揭示了问题的核心。 正如我前面所解释的,SOAP 编码方案将 SOAP 数据模型序列化为 XML。 SOAP 数据模型以非类型化结构图来表示信息,而 XML 架构以类型化元素树来表示信息,那么如何才能将 SOAP 数据模型的编码方案应用到抽象的 XML 架构定义呢? 但是,SOAP 规范(定义了 SOAP 编码)和 WSDL 规范(将 SOAP 编码应用到 XML 架构定义)都没有回答这个问题。 实际上,也没有任何规范说明这意味着什么以及如
何实施。 而这就是问题所在。
返回页首
具体示例
到目前为止,我的论点一直是很理论化的,现在让我给出一个示例以便更实际地加以说明。 考虑以下用于一个名为 Distance 操作的伪代码,该代码用来测量两点之间的距离。
class Point{public Point() {}public Point(int x, int y) { this.x = x; this.y = y; }public int x;public int y;}float Distance(Point p1, Point p2){… // apply the Pythagorean Theorem}
以下是一个 WSDL 文档,它描述一个名为 Geometry 的 portType,该 portType 包含 Distance 操作。 它还定义一个针对Geometry portType 的绑定,该绑定使用 SOAP 编码。
<wsdl:definitionsxmlns:wsdl="/wsdl/"xmlns:xsd="/2001/XMLSchema"xmlns:soap="/wsdl/soap/"xmlns:tns="/team/tewald/sample"targetNamespace="/team/tewald/sample"><wsdl:types><xsd:schema targetNamespace="/team/tewald/sample"><xsd:complexType
陈赫老婆许婧name="Point"><xsd:sequence><xsd:element name="x" type="xsd:int" /><xsd:element name="y" type="xsd:int" /></xsd:sequence></xsd:complexType></xsd:schema></wsdl:types><wsdl:message name="DistanceInput"><wsdl:part name="p1" type="tns:Point" /><wsdl:part name="p2" type="tns:Point" /></wsdl:message><wsdl:message name="DistanceOutput"><wsdl:part name="result" type="xsd:float" /></wsdl:message><wsdl:portType name="Geometry"><wsdl:operation name="Distance"><wsdl:input message="tns:DistanceInput" /><wsdl:output message="tns:DistanceOutput" /></wsdl:operation></wsdl:portType><wsdl:binding name="GeometryBinding" type="tns:Geometry"><soap:binding transport="/soap/http"<wsdl:operation name="Distance"><soap:operation soapAction="" /><wsdl:input message="tns:DistanceInput"><soap:bodynamespace="dotnet/team/tewald/sample"use="encoded" /></wsdl:input><wsdl:output message="tns:DistanceOutput"><soap:bodynamespace="dotnet/team/tewald/sample"use="encoded" /></wsdl:output></wsdl:operation></wsdl:portType></wsdl:definitions>
假设您想要实现一项可公开此 portType 和绑定的服务。 想要您的实现检查其从客户端收到的消息是否与 WSDL 所指定的格式匹配。 如果不匹配,您可以丢弃这些消息并返回一个错误,而不用进行任何其他操作。 那么,正确的消息是由哪些内容组成的呢?
考虑这样一种情况,客户端将两个不同的 Point 实例作为参数传递给Distance 操作,如下所示:
Point one = new Point(10, 20);Point two = new Point(100, 200);float f = proxy.Distance(one, two);
以下是该客户端的已序列化的请求消息。
<soap:Envelope xmlns:soap="/soap/envelope/"><soap:Body soap:encodingStyle="/soap/encoding/"><ns:Distance xmlns:ns="/team/tewald/samples"><p1><x>10</x><y>20</y></p1><p2><x>100</x><y>200</y></p2></ns:Distance></soap:Body></soap:Envelope>
乍一看来,好像很清楚,p1211 985大学是什么意思 和p2 (指定为 夏的偏旁部首ns:Distance 的形参)这两个实例都与 WSDL
文档中 Point 类型的架构定义匹配。 它们各自都有一个具有两个元素(x y )的序列,这两个元素的值都是整数。 但是这个结论并没有充分的依据。 虽然 SOAP 数据模型使用 XML 架构简单类型(例如,xsd:int)来说明单个值(例如,xy),但是它并不使用 XML 架构复杂类型来说明结构化数据(正因如此,所以我说 SOAP 数据模型是基于非类型化结构的)。 如果 SOAP 数据模型不使用 XML 架构复杂类型而 SOAP 编码是基于 SOAP 数据模型的,那么下结论说 p190大寿p2 就是复杂类型 Point 的 SOAP 编码的实例,这样说是否是明智之举吗?