SOAP 1.1 --- 每天发送SOAP request,不搞明白啥叫SOAP,惭愧
SOAP 1.1 XML 架构定义
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://schemas.xmlsoap.org/soap/envelope/" targetNamespace="http://schemas.xmlsoap.org/soap/envelope/" > <!-- Envelope, header and body --> <xs:element name="Envelope" type="tns:Envelope" /> <xs:complexType name="Envelope" > <xs:sequence> <xs:element ref="tns:Header" minOccurs="0" /> <xs:element ref="tns:Body" minOccurs="1" /> <xs:any namespace="##other" minOccurs="0" maxOccurs="unbounded" processContents="lax" /> </xs:sequence> <xs:anyAttribute namespace="##other" processContents="lax" /> </xs:complexType> <xs:element name="Header" type="tns:Header" /> <xs:complexType name="Header" > <xs:sequence> <xs:any namespace="##other" minOccurs="0" maxOccurs="unbounded" processContents="lax" /> </xs:sequence> <xs:anyAttribute namespace="##other" processContents="lax" /> </xs:complexType> <xs:element name="Body" type="tns:Body" /> <xs:complexType name="Body" > <xs:sequence> <xs:any namespace="##any" minOccurs="0" maxOccurs="unbounded" processContents="lax" /> </xs:sequence> <xs:anyAttribute namespace="##any" processContents="lax" /> </xs:complexType> <!-- Global Attributes --> <xs:attribute name="mustUnderstand" default="0" > <xs:simpleType> <xs:restriction base='xs:boolean'> <xs:pattern value='0|1' /> </xs:restriction> </xs:simpleType> </xs:attribute> <xs:attribute name="actor" type="xs:anyURI" /> <xs:simpleType name="encodingStyle" > <xs:list itemType="xs:anyURI" /> </xs:simpleType> <xs:attribute name="encodingStyle" type="tns:encodingStyle" /> <xs:attributeGroup name="encodingStyle" > <xs:attribute ref="tns:encodingStyle" /> </xs:attributeGroup> <xs:element name="Fault" type="tns:Fault" /> <xs:complexType name="Fault" final="extension" > <xs:sequence> <xs:element name="faultcode" type="xs:QName" /> <xs:element name="faultstring" type="xs:string" /> <xs:element name="faultactor" type="xs:anyURI" minOccurs="0" /> <xs:element name="detail" type="tns:detail" minOccurs="0" /> </xs:sequence> </xs:complexType> <xs:complexType name="detail"> <xs:sequence> <xs:any namespace="##any" minOccurs="0" maxOccurs="unbounded" processContents="lax" /> </xs:sequence> <xs:anyAttribute namespace="##any" processContents="lax" /> </xs:complexType> </xs:schema>
如果检查一下 Envelope 的 complexType 定义,你很快就能了解这些元素相互之间是如何关联的。 以下消息模板说明了 SOAP Envelope 的结构:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Header> <!-- optional --> <!-- header blocks go here... --> </soap:Header> <soap:Body> <!-- payload or Fault element goes here... --> </soap:Body> </soap:Envelope>
Envelope 元素始终是 SOAP 消息的根元素。 这就便于应用程序识别“SOAP 消息” — 只要检查一下根元素的名称即可。 通过检查 Envelope 元素的命名空间,应用程序也可确定所使用的 SOAP 版本。
Envelope 元素包含一个可选的 Header 元素(有关详细信息,参见可扩展性一节),后跟一个必要的 Body 元素。 Body 元素代表了该消息的有效内容。 它是一种通用容器,因为它可包含来自任何命名空间的任意数量的元素。 这就是试图发送数据的最终目的地。
例如,以下的 SOAP 消息代表了一个在银行帐户之间转帐的请求:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <x:TransferFunds xmlns:x="urn:examples-org:banking"> <from>22-342439</from> <to>98-283843</to> <amount>100.00</amount> </x:TransferFunds> </soap:Body> </soap:Envelope>
如果接收方支持请求/响应,且能够成功地处理该消息,它应向最初的发送方返回另一条 SOAP 消息。 在这种情况下,响应信息也应包含在 Body 元素中,如下例所示:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <x:TransferFundsResponse xmlns:x="urn:examples-org:banking"> <balances> <account> <id>22-342439</id> <balance>33.45</balance> </account> <account> <id>98-283843</id> <balance>932.73</balance> </account> </balances> </x:TransferFundsResponse> </soap:Body> </soap:Envelope>
该消息处理框架还定义了一个名为Fault 的元素,用于在发生错误时在 Body 元素中表示错误。 这是不可缺少的,因为如果没有一种标准的错误表示方法,每个应用程序将不得不自己创建,从而使得通用基础结构不可能区分成功和失败。 以下示例 SOAP 消息中包含了一个 Fault 元素,指明在处理该请求时发生了“Insufficient Funds(资金不足)”错误:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <soap:Fault> <faultcode>soap:Server</faultcode> <faultstring>Insufficient funds</faultstring> <detail> <x:TransferError xmlns:x="urn:examples-org:banking"> <sourceAccount>22-342439</sourceAccount> <transferAmount>100.00</transferAmount> <currentBalance>89.23</currentBalance> </x:TransferError> </detail> </x:TransferFunds> </soap:Body> </soap:Envelope>
Fault 元素必须包含一个 faultcode,后跟一个 faultstring 元素。 faultcode 元素使用一种符合命名空间的名称对错误进行分类,而 faultstring 元素提供一种对错误可读的解释(类似于 HTTP 的工作方式)。 表 2 简要地说明了 SOAP 1.1 所定义的各种错误码(所有这些代码都包含在http://schemas.xmlsoap.org/soap/envelope/ 命名空间中)。
Fault 元素也可能包含一个 detail 元素,以便提供该错误的细节,这样可以帮助客户端诊断问题,特别是在 Client 和 Server 错误码的情况下。
表 2. SOAP 1.1 错误码
名称
-
VersionMismatch
-
MustUnderstand
-
Client
-
Server
含义
-
处理方发现 SOAP Envelope 元素的命名空间是无效的。
-
处理方没有理解或服从 SOAP Header 元素的某个直接子元素,而该子元素包含一个值为 "1" 的 SOAPmustUnderstand 属性。
-
Client 类的错误表明消息的格式错误或者不包含适当的信息,因而不能成功。 这通常表明,如果不对该消息做出更改,就不应该重发该消息。
-
Server 类的错误表明该消息未能得到处理的原因与消息的内容并没有直接关系,而是跟该消息的处理有关。 例如,处理过程可能包括与某个上游处理器的通信,但该处理器没有响应。 如果在稍后重发,该消息可能会成功。
现在,假设你想在初始的消息中增加一些验证信息,以便接收方能够确定发送方是否有足够的权限来执行传输。 要达到这一目的,一种方法就是在主体中添加凭证信息,如下所示:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <x:TransferFunds xmlns:x="urn:examples-org:banking"> <from>22-342439</from> <to>98-283843</to> <amount>100.00</amount> <!-- security credentials --> <credentials> <username>dave</username> <password>evad</password> </credentials> </x:TransferFunds> </soap:Body> </soap:Envelope>
如果使用这种方法,每项需要验证的操作都必须处理这些凭证。 这也意味着其他需要安全性的应用程序必须开发自己的解决方案以解决这个问题;归根结底,这将损害互操作性。 对于诸如安全性等公共需要,定义各方都同意的标准 SOAP 标头将更有意义。 然后,各厂商可以在其通用的 SOAP 基础结构中建立对扩展功能的支持,这样各方皆赢。 这种方法可提高开发人员的生产力,同时有助于确保更高级别的互操作性。 而这正是 SOAP 扩展性模型设计要实现的目标。