理解 SOAP

简介

就在不久之前,SOAP 还不过是指肥皂而已。 而现在,大多数开发人员一听到这个词眼前就会浮现出一些尖括号来。 SOAP 最初表明“简单对象访问协议”。  若是在几年前问任何一我的 SOAP 的含义,他们极可能这样回答:“SOAP 是用来使 DCOM 和 Corba(例如,RPC 调用)在互联网上工做”。  原做者们也认可,在那时他们注重于“访问对象”,但随着时间的推移,人们但愿 SOAP 可以处理更普遍的状况。 所以,SOAP 规范的重心很快从对象转移到通用的  XML 消息处理框架上。html

这种重心的变化给 SOAP 缩写词中的 "O" 带来了一点小问题。 有意思的是,SOAP 1.2 工做组沿用了(到目前为止)SOAP  这个名称(为何不呢?这个词太流行了),但决定再也不把这个词拼出来以避免误导开发人员。 现在,在最新的 SOAP 1.2 规范中,其正式的定义并不说起对象:web

SOAP 是一种轻量级协议,用于在分散型、分布式环境中交换结构化信息。 SOAP 利用 XML  技术定义一种可扩展的消息处理框架,它提供了一种可经过多种底层协议进行交换的消息结构。  这种框架的设计思想是要独立于任何一种特定的编程模型和其余特定实现的语义。 编程

这个定义确实体现了 SOAP 如今的主旨。 SOAP 定义了一种方法以便将 XML 消息从 A 点传送到 B 点(参见图 1)。 为此,它提供了一种基于 XML  且具备如下特性的消息处理框架:1) 可扩展,2) 可经过多种底层网络协议使用,3) 独立于编程模型。 如下将分别详细讨论这三种特性。数组

ms995800.understandsoap_01(zh-cn,MSDN.10).gif

图 1. 简单的 SOAP 消息处理  安全

首先,SOAP 可扩展性是关键所在。 在这个缩写词还表明某些含义时,"S" 意味着“简单”。 若是咱们从 Web  中学到了同样东西,那就是,简单性老是比效率和纯技术更重要,于是互操做性成败的关键,就在于必须绝对要求简单性。 简单性仍然是 SOAP  的主要设计目标之一,这一点的例证就是 SOAP 缺乏分布式系统的不少特性(如安全性、路由和可靠性等)。 SOAP  定义了一种通讯框架,容许以分层扩展的形式随着时间推移而加入这些特性。 Microsoft、IBM 和其余软件厂商正在积极开发一个 SOAP  扩展的通用套件,该套件将加入大多数开发人员期待的特性。 这一计划被称为全局 XML Web  服务结构 (GXA)Microsoft 已经发布了针对若干 GXA 规范的一个参考实现,并将其命名为 Web  Services Enhancements 1.0 SP1 for Microsoft .NET (WSE)网络

其次,SOAP 可在任何传输协议(诸如 TCP、HTTP、SMTP,甚至是 MSMQ)上使用(参见图 1)。 然而,为了保持互操做性,须要定义一些标准协议绑定以便草拟用于每种环境的规则。 SOAP 规范提供了一种用于定义任意协议绑定的灵活框架,而且因为 HTTP  的使用极为普遍,它现已为 HTTP 提供了一种显式绑定。数据结构

第三,SOAP 容许任何编程模型,而且不依赖于 RPC。 大多数开发人员马上将 SOAP 与对分布式对象进行的 RPC 调用等效起来(由于 SOAP  最初就是关于“访问对象”的),但实际上,基本的 SOAP 模型更接近于传统的消息处理系统,如 MSMQ。 SOAP 定义了一种模型以便处理个别的单向消息。  你能够将多条消息组合成一条总体的消息交换。 图 1 说明了一种简单的单向消息,其中发送方不会收到响应。 可是,接收方能够向发送方发回一条响应(参见图 2)。  SOAP 容许使用任何数量的消息交换模式 (MEP),请求/响应只是其中一种。 其余示例包括要求/响应(与请求/响应相对)、通知和长期运行的点对点对话等。架构

ms995800.understandsoap_02(zh-cn,MSDN.10).gif

图 2. 请求/响应消息交换模式  app

开发人员常常将请求/响应与 RPC 混为一谈,而实际上两者之间的差异很大。 RPC 使用请求/响应,但请求/响应不必定就是 RPC。 RPC 是  一种容许开发人员进行方法调用的编程模型。 RPC 须要将方法签名转换成 SOAP 消息。 鉴于 RPC 的普遍应用,SOAP 草拟了一项协议,以便将 RPC  用于 SOAP(参见本文稍后的RPC 和编码一节)。框架

具有这三种主要特性,SOAP 消息处理框架就促进了在异构环境中交换 XML 消息,而在这类环境中,互操做性长久以来都是极大的挑战。


 

SOAP 版本

从第一个发布的 SOAP 规范到现在被普遍实施的 SOAP 1.1,不少方面都发生了改变,从琐碎的细节到思想的重大转变。 SOAP 1.1 被提交给 W3C,并于 2000 年 5 月被发布为 Note。因为 SOAP 1.1  未能经过 W3C 过程的严格审核,"W3C Note" 状态使其还停留在仅是一个好主意的层次,但当完成时,它将最终达到“推荐”状态。 然而,因为现在 SOAP  1.1 获得了大小厂商如此普遍的支持,它仍然被认为是事实上的标准。

W3C 使用 SOAP 1.1 Note 做为新 XML 协议工做组的基础,负责产生下一版本的 SOAP,目前命名为SOAP 1.2。 SOAP 1.2 当前是一种“候选推荐方案”,意味着它正处在实施阶段且离最后完成为期不远。 一旦 SOAP 1.2  成为“推荐方案”,它极有可能很快得到厂商的支持。

在 SOAP 1.2 发布以后,为了提供向后兼容性,厂商应该继续支持 SOAP 1.1。 SOAP 版本控制基于 XML 命名空间。 SOAP 1.1 由  http://schemas.xmlsoap.org/soap/envelope/ 命名空间标识,而 SOAP 1.2 由  http://www.w3.org/2002/12/soap-envelope 命名空间标识(尽管当其成为推荐方案时,这也将改变)。

有关每一个版本的命名空间名称和规范所在位置,请参见表 1。 在本文的剩余部分中,咱们将讲述 SOAP 1.1 最重要的一些方面。 要了解两个版本之间完整的更改列表,请查看当前的 SOAP 1.2 规范。

表 1. SOAP 版本信息

  • SOAP 1.1

  • 命名空间名称

  • 规范位置

  • SOAP 1.2

  • 命名空间名称

  • 规范位置


 

消息处理框架

SOAP 规范的核心部分就是消息处理框架。 SOAP 消息处理框架定义了一整套 XML 元素,用以“封装”任意 XML 消息以便在系统之间传输。

该框架包括如下核心 XML 元素: Envelope、Header、Body 和 Fault,全部这些都来自 SOAP 1.1 中的  http://schemas.xmlsoap.org/soap/envelope/ 命名空间。 如下代码中提供了 SOAP 1.1 的完整 XML  架构定义,以供在阅读下文时参考。 我我的认为,每次让本身熟悉各类 XML 结构时,检查一下该架构是很有帮助的。

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>

若是检查一下 EnvelopecomplexType 定义,你很快就能了解这些元素相互之间是如何关联的。 如下消息模板说明了  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" 的 SOAP mustUnderstand   属性。

  • 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 扩展性模型设计要实现的目标。


 

扩展性

大多数现有的协议都区分控制信息(例如,标头)和消息有效负载。 在这方面,SOAP 也不例外。 SOAP Header 和 Body 元素在易于处理的 XML  世界中也进行一样的区分。 除了易用性以外,可扩展 Envelope 的关键优点在于它可用于任何通信协议。

在各类应用程序协议中(如 HTTP、SMTP 等)标头老是具备重要的意义,由于标头容许连网两端的应用程序就所支持命令的具体行为进行协商。 尽管 SOAP  规范自己并不定义任何内置的标头,标头将逐渐在 SOAP 中扮演同等重要的角色。 随着 GXA 日趋成熟及 SOAP  标头的标准化,开发人员可以更方便地定义丰富的应用程序协议,而没必要每次都从新开始。

与 Body 元素相似,Header 元素是控制信息的通用容器。 其中可包含来自任何命名空间(除 SOAP 命名空间以外)的任意数量的元素。 放置在  Header 元素中的各个元素被称为标头块。  如同其余协议同样,标头块中包含的信息应该可以影响有效负载的处理。  所以,这里正适于放置诸如凭证一类的元素,以帮助控制对操做的访问:

<soap:Envelope  xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">  <soap:Header>   <!-- security credentials -->   <s:credentials xmlns:s="urn:examples-org:security">    <username>dave</username>    <password>evad</password>   </s:credentials>  </soap:Header>  <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>

咱们也能够利用一个名为 mustUnderstand 的全局 SOAP 属性对标头块进行标注,以指明接收方在处理该消息以前是否须要理解标头。  如下示例说明了如何要求对凭证标头进行处理:

<soap:Envelope  xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">  <soap:Header>   <!-- security credentials -->   <s:credentials xmlns:s="urn:examples-org:security"    soap:mustUnderstand="1"   >    <username>dave</username>    <password>evad</password>   </s:credentials>  </soap:Header>  ...

若是某个标头块被标注为 mustUnderstand="1",而接收方未设计为支持给定的标头,则不该处理该消息,而应该向发送方返回一条 Fault  (带有 soap:MustUnderstand 状态码)。 若是 mustUnderstand="0" 或者没有提供  mustUnderstand 属性,则接收方能够忽略相应的标头块并继续进行处理。 在整个 SOAP 处理模块中,mustUnderstand 属性起着核心做用。


 

处理模型

SOAP 定义了一种处理模型,它大体规定了从 SOAP 发送方传输到 SOAP 接收方的过程当中对 SOAP 消息的处理规则。 图 1说明了最简单的 SOAP 消息处理方案,其中一个应用程序(SOAP 发送方)向另外一个应用程序(SOAP 接收方)发送一条 SOAP 消息。

可是,处理模型容许使用一些更有趣的结构(如图 3 中的结构),这类结构中包含多个中间 节点。 在下文中,将使用 SOAP 节点  这个术语指代任何要处理 SOAP 消息的应用程序,无论是最初的发送方、中间节点仍是最终的接收方;不然,我将明确指出并使用相应的准确术语。

ms995800.understandsoap_03(zh-cn,MSDN.10).gif

图 3. 高级 SOAP 消息处理  

中间节点位于最初的发送方和最终的接收方之间,并截获 SOAP 消息。 中间节点可同时做为 SOAP 发送方和 SOAP 接收方。  中间节点使得有可能设计一些有趣且灵活的网络体系结构,而这些网络结构能受到的消息内容影响。 SOAP 路由就是一个很好的示例,它很大程度上利用了 SOAP  中间节点(有关 SOAP 路由的详细信息,请查看 Routing SOAP Messages  with Web Services Enhancements 1.0)。

在处理消息时,SOAP 节点承担一个或者多个角色 (role),这些角色会影响如何处理 SOAP 标头。 各个角色被赋予独特的名称(以 URI  的形式),以便在处理过程当中可以识别这些角色。 当 SOAP 节点接收到一条要处理的消息时,它首先必须肯定要假定哪些角色。 它能够检查该 SOAP  消息以帮助肯定。

一旦 SOAP 节点肯定了要扮演的角色,它随后必须处理针对其角色之一的全部必要标头(标记为mustUnderstand="1" )。 SOAP  节点也可选择处理针对其角色之一的任何可选标头(标记为 mustUnderstand="0")。

SOAP 1.1 只定义了一个名为 http://schemas.xmlsoap.org/soap/actor/next 的角色(简写为  next)。 每一个 SOAP 节点都必须承担 next 角色。 所以,当 SOAP 消息到达任一给定的 SOAP  节点时,该节点必须处理针对 next  角色的全部必要标头,它能够选择处理针对该 next 角色的可选标头。 除 next  外,SOAP 1.2 定义了另一些角色(参见表 3),且应用程序也能够定义自定义角色。

SOAP 标头经过全局 actor 属性(在 SOAP 1.2 中该属性名为 role )来指定具体的角色。 若是不存在 actor  属性,则标头默认地指向最终的接收方。 如下 SOAP 消息说明了如何使用 actor:

<soap:Envelope    xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">   <soap:Header>     <wsrp:path xmlns:wsrp="http://schemas.xmlsoap.org/rp"     soap:actor="http://schemas.xmlsoap.org/soap/actor/next"     soap:mustUnderstand="1"     >     ...

因为 wsrp:path 标头被指定为 next 角色且被标记为必要的  (mustUnderstand="1"),所以接收到此消息的第一个 SOAP 节点必须根据该标头块的规范来处理此消息,在这种状况下为  WS-Routing。 若是 SOAP 节点不理解针对其角色之一的某个必要的标头,则它必须产生一个带 soap:MustUnderstand  状态码的 SOAP 错误,并中止处理。 SOAP Fault 元素提供了faultactor  子元素,以指定在消息路径中哪一个节点致使了该错误的发生。faultactor  属性的值是一个 URI,用以标识致使该错误的 SOAP 节点。

若是 SOAP 节点成功地处理了一个标头,则它必须从消息中删除该标头。 SOAP 节点能够再插入标头,可是这样作会改变合同方 —  它如今处于当前节点与该标头所指向的下一节点之间。 若是 SOAP 节点刚好是最终的接收方,则它还必须处理 SOAP 主体。

表 3. SOAP 1.2 角色

SOAP 角色名称

说明

  • 每一个 SOAP 中间节点和最终的 SOAP 接收方必须 (MUST) 扮演此角色,并能够 (MAY) 另外承担零个或多个其余 SOAP 角色。

  • SOAP 节点毫不能够 (MUST NOT) 扮演此角色。

  • 要将某个 SOAP 节点确立为最终的接收方,该 SOAP 节点必须 (MUST) 扮演此角色。 SOAP 中间节点毫不能 (MUST NOT) 扮演此角色。


 

协议绑定

图 3中一个有趣之处是 SOAP 容许经过多种底层协议进行消息交换。 因为 SOAP 消息处理框架独立于底层协议,每一个中间节点能够选择使用不一样的通讯协议而不会影响  SOAP 消息。 然而,为了确保各类 SOAP 应用程序和基础结构之间高级别的互操做性,标准的协议绑定是必要的。

一种具体的协议绑定准确地定义了应该如何利用给定的协议来传输 SOAP 消息。 换言之,它详细定义了 SOAP  如何适用于另外一协议的范围,该协议极可能具备本身的消息处理框架以及多种标头。 协议绑定实际所定义的内容很大程度上取决于该协议的功能和选项。 例如,针对 TCP  的协议绑定应很大程度不一样于针对 MSMQ 或针对 SMTP 的协议绑定。

SOAP 1.1 规范仅规范化了一种用于 HTTP 的协议绑定(因为 HTTP 的普遍使用)。 SOAP 已经用于 HTTP  以外的不少协议,可是其实现并未遵循标准化的绑定。 当你尝试与利用相同协议的其余 SOAP  实施进行集成时,只要准备好处理各类互操做性方面的问题,超前一点而不使用标准的协议绑定也何尝不可。


 

HTTP 绑定

HTTP 协议绑定定义了在 HTTP 上使用 SOAP 的规则。 SOAP 请求/响应天然地映射到 HTTP 请求/协议模型。 图 4 说明了 SOAP  HTTP 绑定的不少细节。

ms995800.understandsoap_04(zh-cn,MSDN.10).gif

图 4. SOAP HTTP 绑定  

HTTP 请求和响应消息的 Content-Type 标头都必须设为 text/xml (在 SOAP 1.2 中是  application/soap+xml)。 对于请求消息,它必须使用 POST 做为动词,而 URI 应该识别 SOAP 处理器。  SOAP 规范还定义了一个名为 SOAPAction 的新 HTTP 标头,全部 SOAP HTTP 请求(即便是空的)都必须包含该标头。  SOAPAction 标头旨在代表该消息的意图。 对于 HTTP 响应,若是没有发生任何错误,它应该使用 200 状态码,若是包含 SOAP  错误,则应使用 500


 

RPC 和编码

尽管 SOAP 规范已日渐远离对象,它仍然定义了一种约定,以便利用上述的消息处理框架来封装并交换 RPC 调用。 定义一种标准的方法将 RPC 调用映射到  SOAP 消息,这使得在运行时基础结构能够在方法调用和 SOAP 消息之间自动转换,而不用围绕 Web 服务平台从新设计代码。

要利用 SOAP 进行方法调用,基础结构须要如下信息:

  • 1.终结点位置 (URI)

  • 2.方法名称

  • 3.参数名称/值

  • 4.可选的方法签名

  • 5.可选的标头数据

这些信息能够经过多种方法来传输,包括类型库、IDL 文件,或者,更好的是 WSDL 文件。 SOAP RPC 绑定定义了如何在 SOAP  主体中封装并表示这些信息。 为此,RPC 绑定首先定义如何将方法签名映射到简单的请求/响应结构,而后将这些结构以 XML 进行编码。 RPC  绑定规定将以一个按照方法命名的 struct 来模拟该方法调用。 该结构将包含对应于每一个 [in] 或  [in/out] 参数的一个访问器,访问器的名称与参数名相同,其次序由消息签名肯定。 方法响应也将做为一个结构来建模。  结构的名称可有可无,尽管约定是使用方法名后跟 "Response"(例如,对于 add 操做,方法响应名应该相应为  addResponse)。 响应结构包含一个用于返回值的访问器(其名称在 SOAP 1.1 中可有可无,但在 SOAP 1.2 必须是  rpc:result),其后是针对每一个 [out][in/out] 参数的访问器。

让咱们来看一个示例。 假设 add 操做具备如下的 C# 方法签名:

double add(ref double x, double y)

根据刚才所说明的 RPC 绑定规则,表明该方法调用的请求结构应以下建模:

struct add {   double x;   double y; }

而响应结构以下:

struct addResponse {   double result;   double x; }

如今的问题是: 应该如何将这些结构映射到 XML(R) SOAP 规范定义了一组编码规则,专门用于此用途。 SOAP  编码规则大体阐述了如何将当今最经常使用的数据结构(如结构和数组)映射到普通的 XML 格式。 根据 SOAP 编码规则,以上的请求结构应映射到如下 XML  消息(这将放在 SOAP 主体中):

<add>   <x>33</x>   <y>44</y> </add>

且上述请求的响应消息将映射到如下 XML 消息(这个消息将进入响应消息的主体):

<addResponse>   <result>77</result>   <x>33</x> </addResponse>

XML 架构的相关工做刚刚开始,SOAP 编码规则即已创立。 既然 XML 架构已经完成,开发人员能够简单地提供文字的 XML 架构定义,从而准确指定应该如何以  XML 来格式化请求/响应消息。 因为利用 XML 架构定义更易于得到互操做性,所以大多数开发人员已经决定彻底摒弃 SOAP 编码规则。 实际上,自 SOAP  1.2 起,SOAP 规范再也不正式要求支持 SOAP 编码规则。 从如今起,最好避免使用 SOAP 编码规则,有关此中起因的全面讨论,请查看关于 SOAP 编码的讨论一文。

尽管 SOAP RPC 绑定和编码规则为那些不肯意涉及诸如 XML 架构和 WSDL 等的应用程序提供了一个很好的 SOAP 集成层,由于 RPC  绑定和编码规则易于致使互操做性方面的问题,它们基本上已经失宠于 Web 服务社区。


 

SOAP 类型

要重申的是,现在有两种基本类型的 SOAP 消息处理: 文档和 RPC。 文档类型指出主体只是包含一个 XML 文档,而发送方和接收方都必须遵循该文档的格式。  另外一方面,RPC 类型指出主体中包含某个方法调用的 XML 表示,正如刚才所述。

两种方法可用于肯定如何将数据序列化到主体中: 使用文字的 XML 架构定义和使用 SOAP 编码规则。 利用前一种方法,架构定义逐字肯定了主体的 XML  格式,不具备二义性。 然而,利用后一种方法,SOAP 处理器必须在运行时遍历各类 SOAP 编码规则以肯定主体正确的序列化。  很显然,这种方法更易于致使错误和互操做性方面的问题。

最多见的情形是在使用文档类型时也使用文字架构定义(称为文档/文字),以及在使用 SOAP 编码规则时使用 RPC 类型(称为  rpc/编码)。 文档/编码和 rpc/文字也是可能的,但并不常见,也没有太大意义。 大多数 Web  服务平台都集中于文档/文字类型,将其做为发展的主要用例,且是现今 Microsoft ASP.NET WebMethod 框架的默认设置。


 

小结

SOAP 定义了一种简单而可扩展的 XML 消息处理框架,它能够经过多种协议用于各类不一样的编程模型,尽管此规范中规范化了如何将 SOAP 用于 HTTP  和 RPC 调用。 SOAP 还定义了一个完整的处理模型,大体规定了当消息沿路径传送时如何对其进行处理。 总的来讲,SOAP  提供了一个功能丰富而灵活的框架以便定义高级应用程序协议,这些协议可在分布式异构环境中提供更好的互操做性。

相关文章
相关标签/搜索