级别: 初级 关于作者 (gl2_public@sina.com), Technical Manager
2001 年 6 月 01 日 布式多层系统是目前在企业级大中型应用中最流行的架构,而XML则是计算机数据处理的最新技术,强强联手能产生多大的化学效应;作为新的数据处理标准,XML的通用性与开放性勿庸置疑,不过对于传统成熟的开发模式,XML的价值是在于锦上添花,还是将取而代之;作为一名开发人员,我们相信通过XML可以整合与优化系统的总体性能,为了实现这个目标,在设计中要采取哪些步骤,又需要注意哪些误区……本篇就B2B供应链系统应用模型的设计为实例,试图为上述疑问寻求解答。
SOAP协议
SOAP是一种基于XML-RPC的改进版本,我们可以称之为XML-RPC++,它是微软、IBM等业界巨擘力推的下一代互联网数据传递协议,正如其在W3C发布的SOAP草案中所描述的:"SOAP的目标是通过XML建立一个用于在分布式松散耦合网络环境中交换结构化及已定义类型数据的轻量级协议"。
整个SOAP协议规范由三部分组成:
- SOAP封装(envelope):定义了一个整体框架用来表示消息中包含什么内容,谁来处理这些内容以及这些内容是可选的或是必需的。
- SOAP编码规则(encoding rules):定义了用以交换应用程序定义的数据类型的实例的一系列机制。
- SOAP RPC表示(representation):定义了一个用来表示远程过程调用和应答的协定。
首先让我们来看如下的一段SOAP范例:
基于HTTP的SOAP请求:
POST /StockQuote HTTP/1.1
//请求报头
Host: 202.96.96.44
Content-Type: text/xml; charset="utf-8"
Content-Length: nnnn
SOAPAction: "http://www.sign.com/soap"
SOAPMethodName: http://sign.com/soap # GetLastTradePrice
<SOAP-ENV:Envelope
//请求报文
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Header>
//SOAP头
<m:Transaction xmlns:m=" http://sign.com/soap" SOAP-ENV:mustUnderstand="1">
<Number>10</Number>
</m:Transaction>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
//SOAP体
<m:GetLastTradePrice xmlns:m='' http://sign.com/soap '' >
<symbol>DIS</symbol>
</m:GetLastTradePrice>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
|
上述SOAP请求的响应:
HTTP/1.1 200 OK
//响应报头
Content-Type: text/xml; charset="utf-8"
Content-Length: nnnn
<SOAP-ENV:Envelope
//响应报文
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
<SOAP-ENV:Body>
<m:GetLastTradePriceResponse xmlns:m='' http://sign.com/soap ''>
<Price>34.5</Price>
</m:GetLastTradePriceResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
|
SOAP请求是一个HTTP POST请求。SOAP请求的内容类型(content-type)必须使用text/xml。一个SOAP HTTP请求头中的SOAPAction域用来指出这是一个SOAP HTTP请求,它的值是所要的URI。在格式、URI的特性和可解析性上没有任何限制。当HTTP客户发出SOAP HTTP请求时必须使用在HTTP头中使用这个域。服务器怎样解释这个请求-URI是与实现相关的,但是在许多实现中可能用它来映射到一个类或者一个对象。如果SOAPAction域的值是空字符串(""),表示SOAP消息的目标就是HTTP请求的URI。如果SOAPAction域没有值表示没有SOAP消息目标的信息。
一个SOAP请求用SOAPMethodName来指明将被调用的方法。即SOAPMethodName是被URI指定范围的应用相关的方法名,它是用#符作为分隔符将方法名与URI分割开,在上述SOAP请求范例中的SOAPMethodName语句表明其方法名是GetLastTradePrice,范围URI是http://sign.com/soap。SOAPMethodName头必须与
下的第一个子元素相匹配,否则调用将被拒绝。这允许防火墙管理员在不解析XML的情况下有效地过滤对一个具体方法的调用。
与XML-RPC相同,SOAP的消息报文是一个XML文档,它包括一个必需的SOAP封装,一个可选的SOAP头和一个必需的SOAP体。一个SOAP消息包括以下部分:
- 顶层元素"Envelope"(SOAP封装):可以包含名域声明和附加属性。如果包含附加属性,这些属性必须限定名域。类似的,"Envelope"可以包含附加子元素,这些也必须限定名域且跟在SOAP体元素之后。
- 一级子元素"Header"(SOAP头):在SOAP消息体中可能出现。如果出现的话,必须是SOAP
- 封装元素的第一个直接子元素。SOAP头可以包含多个条目,每个都是SOAP头元素的直接子元素。所有SOAP头的直接子元素都必须限定名域。使用SOAP交换消息的各方是分散且没有预先协定的,SOAP头提供了向SOAP消息体中添加关于SOAP消息的某些特征的(feature)机制。SOAP规范中定义了一些属性用来表明某项特征(feature)是否可选以及由谁来处理。(见4.2节)
- 一级子元素"Body"(SOAP体):在SOAP消息中必须出现且必须是SOAP封装元素的直接子元素。它必须直接跟在SOAP头元素(如果有的话)之后。否则它必须是SOAP封装元素的第一个直接子元素。SOAP体可以包括多个条目(entry),每个条目必须是SOAP体元素的直接子元素。
有关SOAP封装、SOAP头、SOAP体三者基本关系的Schema定义如下:
<schema targetNamespace=''urn:schemas-xmlsoap-org:soap.v1''>
<element name=''Envelope''>
<type>
<element name=''Header'' type=''Header'' minOccurs=''0'' />
<element name=''Body'' type=''Body''minOccurs=''1'' />
</type>
</element>
</schema>
|
一个SOAP应用程序产生的消息中,所有由SOAP定义的元素和属性中必须包括正确的名域。SOAP应用程序必须能够处理它接收到的消息中的SOAP名域(见4.4节),并且它可以处理没有SOAP名域的SOAP消息,就象它们有正确的名域一样。在SOAP1.1规范中定义了两个名域:
在SOAP封装中使用EncodingStyle全局属性来表示SOAP消息的编码规则。这个属性可以在SOAP封装的任何元素中出现,其作用范围为这个元素的内容和它的所有没有重载此属性的子元素。EncodingStyle属性值可以是一个或多个URI的顺序列表,每个URI确定了一种或多种编码规则,用来不同程度反序列化SOAP消息,举例如下:
- "http://schemas.xmlsoap.org/soap/encoding/"
- "http://my.host/encoding/restricted http://my.host/encoding/"
其中最后一个零长度的URI("")明确显示所含元素没有任何编码形式。这可以用来取消上一级元素的所有编码声明。
我们将专用于SOAP头(Header)的属性称之为头属性,包括actor属性与mustUnderstand属性。SOAP头属性指定了SOAP消息的接收者应该怎样处理SOAP消息。产生SOAP消息的SOAP应用程序,应该仅仅在SOAP头元素的直接子元素中使用这些SOAP头属性。SOAP消息的接收者必须忽略所有不在SOAP头元素的直接子元素中SOAP头属性。
在SOAP头中使用actor全局属性来指示头元素的接收者。SOAP actor属性的值是一个URI。一个SOAP消息从客户端到服务器的发送过程中,可能沿着消息路径经过一系列中间节点,所谓中间节点是一个可以接收转发SOAP消息的应用程序。在SOAP actor属性中使用URI来区分节点。省略SOAP actor属性表示接收者是SOAP消息的终节点。在绝大多数情况中,头属性的接收者都是SOAP的终节点。
在SOAP头中使用 mustUnderstand全局属性来指示接受者在处理消息时这个条目是否必须处理(条目的接收者由SOAP actor属性定义)。MustUnderstand属性的值是"1" 或 "0",缺少SOAP mustUnderstand属性在语义上等同于它的值为"0"。
SOAP体是包含消息的最终接收者想要信息的容器。SOAP体提供了一个简单的机制,使消息的最终接收者能够得到并交换必要的信息。SOAP体的所有直接子元素称作体条目(Body Entry),每个体条目在SOAP体元素中为一个独立的子元素。体条目的编码规则如下:
- 一个条目(entry)由它的元素全名(包括名域URI和局部名)确定,SOAP体条目可以是有名域限制的;
- 可以使用SOAP encodingStyle属性来指示体条目的编码方式;
- SOAP体中定义了一个Fault体条目专门用来报告错误信息。
正如我们前面所说的,SOAP是XML-RPC的改进版本,因此如何通过SOAP实现远程方法调用也可以说是整个SOAP规范的核心,在SOAP中方法调用和应答都包含在SOAP Body元素中,它们使用如下的表示形式:
- 每一个方法调用与方法响应(包括错误响应)都必须是SOAP体的一个条目(直接子元素);
- 一个方法调用通过一个结构类型(有关SOAP中结构类型将在后面描述)表示;
- 一个方法调用被看作一个单个的结构,包含方法中所需参数的值。这些值被编码成为一个调用元素的子元素;
- 在SOAP方法调用元素(结构类型)中,每个参数的名和类型与所调用方法的参数名和类型相对应,它们的出现顺序和调用方法中定义的参数顺序相同。
- 一个方法应答用一个结构表示。
- 一个方法应答被看作单个的结构,返回值与每个参数均被被编码成为一个方法响应元素的直接子元素。第一个直接子元素是返回值,之后是参数,参数的出现顺序和方法中定义的参数顺序相同。
- 响应元素中每个参数的名称和类型与所调用方法的参数名称和类型相对应。返回值的名称并不重要。同样,结构的名称也不重要,不过,通常在方法名称的后面加上字符串"Response"作为结构的名称。
- 在SOAP响应中,当方法调用错误时使用SOAP
- Fault元素表示。如果绑定的协议有额外的规则表示错误,则这些规则也必须要遵从。
SOAP编码规则基于一个简单的数据类型系统,它综合了程序语言,数据库和半结构化数据等类型系统的共同特性。在XML1.1规范中允许非常灵活的数据编码方式,而在SOAP规范中定义了一个较小的规则集。在SOAP1.1规范中通过名域标志符定义了一个缺省的编码规则即:http://schemas.xmlsoap.org/soap/encoding/,同时在SOAP规范中还允许在SOAP封装的任意元素中通过encodingStyle全局属性来使用其它第三方的编码规则。
在SOAP缺省编码规则中提供对如下数据类型的支持:
- 简单数据类型
-
- 整型:int
- 浮点型:float
- 负整型:negativeInteger
- 字符串:string
- 构造数据类型
-
- 枚举型:enumeration
- 数组型:array
- 结构型:struct
- 变量:用于表示可能包含多种数据类型的元素,在SOAP中仅用于数组类型声明。
- 在SOAP中要指定元素值的数据类型主要有三种方式:
- 使用一个直接子元素表示数据类型;
- 使用xsd:type属性(xsd可以用其它名域前缀替换);
- 元素名具有特定的类型,类型通过schema指定。一个schema和对应具有这些类型的元素的数据实例的例子如下所示:
-
Schema片断:
<element name="age" type="int"/>
<element name="height" type="float"/>
<element name="displacement" type="negativeInteger"/>
<element name="color">
<simpleType base="xsd:string">
<enumeration value="Green"/>
<enumeration value="Blue"/>
</simpleType>
</element>
|
SOAP实例片断:
<age>45</age>
<height>5.9</height>
<displacement>-450</displacement>
<color>Blue</color>
|
当SOAP报文的方法调用或传输错误时,在其响应报文中会返回一个错误,如我们在前面所说的,SOAP使用一个专门的错误元素(Fault)来封装错误信息。SOAP错误元素必须以体条目的方式出现,并且在一个体元素中最多出现一次。在SOAP错误元素中定义了以下四个子元素:
- faultcode:faultcode元素给软件提供了一个识别此错误的算法机制。SOAP错误元素必须有faultcode子元素。faultcode的值必须是一个合法的名。SOAP规范中定义一些SOAP faultcode描述基本的SOAP错误。
- faultstring:faultstring元素提供了一个对错误的解释。SOAP错误元素必须有faultstring子元素,并且它应该提供一些错误本质的解释信息。
- faultactor:faultactor元素的值是一个URI,它指出在消息路径上是哪个节点导致了错误发生的信息。当在中间节点产生错误时SOAP Fault元素中必须包含faultactor子元素。而SOAP消息的最终目的地也可以使用faultactor元素明确指示是它产生了这个错误。
- detail:detail元素用来携带与SOAP体有关的错误信息。如果SOAP体元素的内容不能被成功的处理,则在SOAP
- Fault元素中必须包含detail子元素。它不能用来携带属于头条目的错误信息。Fault元素中没有detail元素表示这个错误与Body元素的处理无关。detail子元素可以用来区分Body元素有没有被正确的处理。
研究SOAP的初衷源于开发人员在使用XML-RPC过程中的局限性,因此我们有必要回过头来看一下XML-RPC存在的一些不足以及SOAP对其所作的改进。
- 冗长的数据类型定义。在XML-RPC中充斥着大量的<value>与<data>等元素,以数组类型为例,一个可能的XML-RPC数组如下所示:
<value>
<array>
<data>
<value><int>1</int></value>
<value><int>2</int></value>
<value><int>3</int></value>
<value><int>4</int></value>
</data>
</array>
</value>
|
而在SOAP中对应的数组则可表示如下:
<array>
<int>1</int>
<int>2</int>
<int>3</int>
<int>4</int>
<array>
|
- 数据类型的限制。在XML-RPC中数据类型是有限不可扩展的,而对于某些复杂的应用这些数据类型是远远不够的。而且不同编程语言的数据类型都不尽相同,在将其数据转换到XML-RPC格式时,有时必须使用强制数据类型转换,从而使数据的表示丧失了许多原有的特性。SOAP在这方面有很大提高,它参考了W3C最近工作草案的"XML Schema Part 2"部分,提供了一些新的数据类型如枚举、变量以及更灵活的数组定义,另外它还允许用户定义自己的数据类型。
- 相同值的多处引用。如果有一个元素值在报文中被多处提及,比如说某一份采购单有上百种原料采购,而其中的四十种原料都向同一个厂家定购,如果在每一种原料后都要注明供应商,那么……在XML-RPC中我们不得不重复这个厂家的全称四十次。在SOAP中采取了"多引用"技术(multi-reference)来解决此问题,我们可以采用如下的SOAP报文片断来表示上述的采购单:
<OrderForm>
<material>
<name>彩电</name>
<model>E021</model>
<number>100<number>
<provider href="#1"/>
</material>
<material>
<name>收录机</name>
<model>E22</model>
<number>50<number>
<provider href="#1"/>
</material>
.......
.......
</OrderForm>
<provider id="1">厦华电器</provider>
|
- 扩展的HTTP报头支持。在消息报文被处理前,HTTP扩展模式允许一个报头列表被一个服务器或代理所理解。我们可以在报头中指定一个功能调用所需要的参数(称之为强制性报头),如果服务器不理解强制性报头,那么它会拒绝全部的调用。在SOAP中支持HTTP扩展模式,即可以通过在SOAP报头首行使用M-POST(动词POST加前缀"M-")来表示其使用了强制性报头。这将使一个理解HTTP扩展模式的接收端在报头中寻找一个被称为"Man"的单行,该行包含一个URI表示命名空间和一个数字用于代表该命名空间。该数字作为强制性报头SOAPMethodName的前缀,以指定SOAPMethodName的命名空间,此时服务器必须能识别SOAPMethodName,否则服务器将不处理该消息。以下是一个支持HTTP扩展模式的SOAP报头示例:
M-POST /StockQuote HTTP/1.1
Host: www.ichain.com
Man: "urn:schemas-xmlsoap-org:soap.v1; ns=42"
42-SOAPMethodName: http://sign.com/soap#gettradeprice
|
- 改进的错误报告。在XML-RPC中采用faultCode与faultString子元素来表示错误信息,而在SOAP中由于添加了faultactor与detail子元素,使得关于错误的描述可以更为精确。
有关SOAP协议的最新版本可到以下网址
http://www.w3.org/TR/SOAP查看。以下是SOAP的开发工具包链接清单:
关于作者  | 
|  | 郭路,杭州大学计算机系92届本科应用专业,曾先后就职于浙江省纺织经贸总公司计算机中心、思能软件、华企、飞时达等软件公司,担任技术主管,主要从事于企业 MIS、GIS、ERP 及电子商务项目的开发管理和系统分析,对 IBM、微软、SUN、Autodesk 等公司的企业级产品有较深的研究及理解。
mailto:gl2_public@sina.com
|
对本文的评价
|