<3> soap的相关技术标准

二、 soap的有关技术标准
soap是Simple Object Access Protocal(简单对象访问协议)的简称,它是一种应用程序之间进行数据通信的机制。是一种轻量的、简单的、基于 XML 的协议,它被设计成在 WEB 上交换结构化的和固化的信息。 SOAP 可以和现存的许多因特网协议和格式结合使用,包括超文本传输协议( HTTP),简单邮件传输协议(SMTP),多用途网际邮件扩充协议(MIME)。

SOAP定义了三部分内容:
1.一个打包模型(即soap 封套)。
2.一种对信息进行串行化的机制(即soap信息编码规则)。
3.一个RPC机制(即soap中的RPC表示法)。


制定soap标准的专家组是按这三个部分协同工作而设计的,可程序员单独使用其中的某个部分也未尝不可。比如说,某个程序可以使用soap编码规则来保存配置文件;某个及时信息系统也可以使用soap的打包模型在谈话双方传递数据;而RPC方面的应用则可以忽略soap封套,只使用其编码规则和RPC表示法来实现函数调用。

2.1 基本知识
soap标准v1.1版介绍了如何把http和soap结合在一起使用。这只是为了对如何在一种传输机制上实现soap进行规范。前面说过,它还可以在其他协议上传输。
soap标准v1.1版本定义了两种名字空间前缀,他们是:
SOAP-ENV:对应的URI是 http://schemas.xmlsoap.org/soap/envelop/
SOAP-ENC:对应的URI是 http://schemas.xmlsoap.org/soap/encoding/
第一个主要是soap元素的命名空间,第二个主要是编码命名空间。

在这份标准里还大量使用了两种现有的名字空间:
xsd:对应的URI是 http://www.w3.org/2001/XMLSchema/
xsi:对应的URI是 http://www.w3.org/2001/XMLSchema-instance/
第一个是xml标准中定义的数据类型的命名空间,第二个是一个特定的实例中用到的数据类型的命名空间。

2.2 xml类型的编码规则
为了避免程序员随意选择一种编码方案来使用,soap标准对这些常见数据的编码方法做出了规定。这些规则的作用体现在两个方面。
第一:对任意一项遵守soap数据类型定义办法的大纲我们对能相应地构造出一条xml语法来。
第二:用这项大纲和soap消息体中的一个元素应用程序就能为某个特定的数据项创建一个xml实例来。
为了让soap应用程序知道你用的是正常的编码规则,必须把编码方案的URI设置为:
http://schemas.xmlsoap.org/soap/encoding/。

本节的学习重点是编码技术。我们大概知道只要给所有的元素加上” xsi:type”属性就能实现对信息的编码工作。没错,这个办法的确能够让我们把元素的类型和结构准确地描述出来,不需要其他任何描述属性。编码规则说的很清楚,一个值的类型完全是由相关的大纲引用指针确定的。具体含义我们先来看个例子,假设有一个下面这样的复合值:
<product kind=”utensil”>
    <productName>fork</productName>
    <price>1.25</price>
</product>

那么其中的”kind”是一个枚举值还是一个字符串呢?”productName”呢?”price”是一个字符串还是一个浮点数?没有大纲,是回答不了这些问题的。现在,如果有了下面这样的大纲(假设保存在一个名为schema.xml的文件里):
<xsd:schema xmlns:xsd=http://www.w3.org/2001/XMLSchema
xsd:targetNamespace=”http://www.scottseely.com/product”>
<simpleType name=”kind” base=”xsd:string”>
    <enumeration value=”utensil” />
<enumeration value=”flatware” />
<enumeration value=”china” />
</simpleType>
<complexType name=”product” context=”mixed”>
    <element type=”kind” />
    <element type=”productName” />
    <element type=”price” />
</complexType>
<element name=”productName” type=”xsd:string”></element>
<element name=”price” type=”xsd:float”></element>
</xsd:schema>

然后再像下面这样对数据进行编码:
<x:product xmlns:x=http://www.scottseely.com/product
xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance
xsi:schemaLocation=”http://www.scottseely.com/product.xsd”>
    <x:productName>fork</x:productName>
    <x:price>1.25</price>
    <x:kind>flatware</x:kind>
</x:product>

那些值的类型就能够定下来了。

xsi:schemaLocation用于指定一个命名空间和对应的xsd文件的关联,可以参考:
http://www.w3schools.com/schema/schema_schema.asp
http://blog.csdn.net/zhengyeqing520/article/details/6091656

2.3 soap信息交换模型
soap信息是一种从发送方到接收方的单向传输机制。这种设置使soap能够在smtp等单向通信协议上得到实现。单向传输机制对处理远程RPC帮不上什么忙,因为调用方总是会期待某种形式的响应。在大多数情况下,soap信息都是把一个请求模式和一个响应模式结合在一起实现的。soap标准的第1.3节“soap信息示例”给出一个这方面的例子:
http请求:


部分响应:


其中的some-uri声明表示那里应该放上一个真正的uri,他们起码是标准的xml名字空间。在上面的请求和响应组合里,整个信息都包含在” SOAP-ENV:Envelop”起始和结束标记之间。在大部分的SOAP示例里都会看到有SOAP-ENV用作命名空间的现象,但这并不意味着必须这样做,也可以使用MY-SOAP-NAMESPACE或者其他任何合法的名字空间字符串作为SOAP命名空间的名字。

2.4 soap信息的结构
一切soap信息都是xml文档。他们必须有一个soap封套和一个信息体。他们还可以有一个可选的soap头。


2.4.1 soap封套
封套是soap信息里最外层的包容元素。他们必须遵守以下语法规则:
1.这个元素的名字永远是Envelop.
2.每条soap信息必须包含在这个元素并把它作为最外层的包容元素。
3.这个元素可以有命名空间声明并附带其他属性。包容在此元素内的所哟属性都必须有名字空间方面的限定。Envelop元素还可以包含子元素。类似于其附加属性,Envelop的子元素也都要有命名空间限定,而且他们的后面必须紧跟soap body元素。

在Envelop元素里,我们可以通过 encodingStyle属性来指定编码风格,soap信息里所有其他的元素也有类似的属性。 在soap信息封套,信息头和信息体这三个部分里都可以使用encodingStyle这个属性。

出于兼容性方面的理由,soap有一个 版本核查机制。版本核查机制的传统用法是在应用程序的范畴内照顾向后兼容的问题。这种机制中的大多数都采用主版本号加辅版本号这样一种模型。比如,版本号是1.1,其中主版本号是1,辅版本号也是1。可soap 不通过数字来进行版本核查,它必须使用一个与http://schemas.xmlsoap.org/soap/envelop/命名空间相关联的Envelop元素。如果某个信息为其封套指定的是其他名字,他就会被当做一个版本不匹配的情况来处理。只要出现了这种情况,soap应用程序就必须用一条出错代码为VersionMismatch的出错信息向调用方作出响应,而这条错误信息的名字空间必须是http://schemas.xmlsoap.org/soap/envelop/。

2.4.2 soap信息头
soap信息头可以出现在soap信息里,也可以不出现。这个可选项提供了这样一种机制:soap信息可以通过它把这条信息本身的信息传递给其他信息。 如果soap信息头出现在soap信息里,它必须是soap Envelop元素的第一个子元素。
那么什么时候需要信息头呢?最常见的情况使用Header来对调用方进行 身份验证,或者用它来提供对通信过程的管理。对没有提供返回路径的协议(比如FTP)来说,Header还可以用来协调响应的返回路径。

Header的一级子元素必须使用一个完全限定的元素名。这个名字必须由一个命名空间URI和一个本地名字组成。根据XML的有关规定,应用程序会认为那些包含在Header的一级子元素里的一切元素都在同一个命名空间里。下面的例子就是使用Header元素来为FTP传输提供响应的返回路径。下面两段代码是等价的:
一、从头到尾都使用了命名空间:
<SOAP-ENV:Header>
< ftpNS:soapFTPRequest xmlns:ftpNS=http://www.scottseely.com/ftpNS
SOAP-ENV:mustUnderstand=”1”>
        < ftpNS:responseLocation>
            < ftpNS:ftpSite>ftp://mysite.com</ftpNS:ftpSite>
            < ftpNS:ftpDir>soapResponse/myApp</ftpNS:ftpDir>
            < ftpNS:userName>myAppUser</ftpNS:userName>
            < ftpNS:password>pwd</ftpNS:password>
        < /ftpNS:responseLocation>
    < /ftpNS:soapFTPRequest>
</SOAP-ENV:Header>

二、只在一级元素上使用了命名空间
<SOAP-ENV:Header>
< ftpNS:soapFTPRequest xmlns:ftpNS=http://www.scottseely.com/ftpNS
SOAP-ENV:mustUnderstand=”1”>
        < responseLocation>
            <ftpSite>ftp://mysite.com</ ftpSite>
            < ftpDir>soapResponse/myApp<ftpDir>
            < userName>myAppUser<userName>
            <password>pwd</password>
        </responseLocation>
    < /ftpNS:soapFTPRequest>
</SOAP-ENV:Header>

除了encodingStyle属性以外,一级子元素还可以使用mustUnderstand或actor属性。如果这两个属性时出现在Header里面的非一级子元素上,信息的接收方将忽略他们。
1.SOAP-ENV:mustUnderstand属性
这个属性的取值可以是“0”(如果这个元素没有意义,可以跳过继续处理后续元素)或“1”(如果这个元素没有意义,就停止整个处理,返回出错信息)。如果Header的子元素里没有包含这个属性,接收方的应用程序将按照“0”的情况处理。

2. SOAP-ENV:actor属性
soap信息可能需要穿越几个中间环节才能到达最终的目的地。这里的“中间环节”指的是信息旅途上的其他一些soap应用程序,他们能够接受和转发soap信息。在每一个中间环节,接收到这条信息的soap应用程序会检查信息头,看看这条信息里有哪些东西是发给自己的,谁又是下一个接收者。这些中间环节和最终的目的地都必须用URI标识出来。” SOAP-ENV:actor”属性给出的就是信息头在这些中间环节上扮演的“角色”。当信息头从一个角色转换为另一个角色时,必须遵守一套处理规则。

首先信息在旅途上的每个中间环节得到一些处理。但在把信息转发给下一个处理者之前,中间环节上的SOAP应用程序要把自己处理的信息片段从信息上取下来。信息的接收者通过查找取值的URI为 http://schemas.xmlsoap.org/soap/actor/next/的actor属性来判断需要自己对哪些信息头元素进行处理(后面看到实例会更清楚,soap 1.1规定只有这一个有效的actor标识)。对”actor”属性应该永远使用一个URI作为它的值。应用程序通过这一机制来完成需要多项soap服务联手才能完成的处理。下面是通过信息头对订单进行处理的例子。我们假设客户程序知道订单将会怎样处理,但只有在整个订单落实之后才需要一个响应。沿着订单的整个处理流程看一下。
1.最初的客户请求


第一步,soap应用程序读取这条信息。通过检查信息头,它知道自己只需要处理第一个信息头,因为该部分使用的是正确的URI。虽然另外两个信息头的mustUnderstand属性页设置为”1”,但因为他们的actor取值 不是http://schemas.xmlsoap.org/actor/next/ ,所以第一个应用程序必须忽略他们。第一个信息头告诉第一个接收者要由它标识为”cust”的信息体元素所提供的信息来填上”customId”。在完成这一步处理后,信息的信息头和信息体都发生了一点变化。

2.将转发到订单处理系统(即http://www.scottseely.com/placeOrder)去的信息:


3. 将转发到货物配送系统(即http://www.scottseely.com/shipOrder)去的信息:


2.4.3 soap信息体
信息体(Body)可以看做是soap的内容核心。它包含准备发送给接收方的具体信息内容。它最初是处理RPC返回出错信息(即soap的“Faults”信息)而安排的。但自从它出现,人们就开始利用他来传递其他类型的数据。放在Body元素中的任何数据都应该使用soap编码规则。后面会重点介绍这部分。

2.4.4 soap错误
在Envelop元素三个主要的子元素中,只有Body有一个预先定义好的子元素“Fault”。soap应用程序可以利用Fault元素在信息里运送出错信息和状态信息。应该只在信息响应里使用这个元素。当这个元素出现的时候,必须放在信息的信息体里,而且只能出现一次。Fault又定义了四个子元素:
1.faultcode,错误代码,必须包含。
2.faultstring,错误原因,必须包含。
3.faultactor,错误报告者,报告这条出错纤细是soap信息旅途中的哪个soap应用程序写的。可选。
4.detail,详细资料。这个元素给出的是Body元素方面的错误的详细资料,具体内容由应用程序给出。如果soap应用程序不能对信息体的内容进行处理,就必须在Fault元素里加上这个子元素;如果Fault描述的问题只是与信息头Header项的处理相关,soap应用程序就不能填写此项数据。知道了这条规则,当在Fault信息里看到这个元素时,就会明白问题出在信息体里。如果没有出现,就意味着问题出在别的地方。
与其他soap元素一样,soap应用程序在定义Fault元素的时候必须使用它的完全限定名”SOAP-ENV:Fault”。

2.4.5 soap信息的处理流程
soap应用程序必须按一系列的流程对soap信息进行处理。这个流程对不同实现方式的soap系统在行为方面进行了统一规范。下面是在soap技术标准第2小节规定的流程:
1.把soap信息中所有与本应用程序有关的元素识别出来。
2.对第一步识别出来的元素进行检查,看本应用程序是否支持这条信息,然后按顺序进行处理。如果不能对这条信息进行处理,就丢弃这条信息。
3.如果本soap应用程序不是这条信息的最终目的地,在转发信息之前去掉步骤1识别出来的所有元素。
对信息或信息的一部分进行处理要求soap应用程序理解以下几个问题:
1)信息使用的数据交换模式
2)接收方在此数据交换模式中的角色
3)信息使用的RPC机制(如果有的话)
4)数据的编码方案
5)为正确处理此信息要求应用程序理解的语法

2.5 在http中使用soap
本节集中在http上的soap,这是如何在能够提供一个请求/响应信息模型的协议上实现soap的绝佳例子。从原理上讲,soap是一个跨在其他应用程序协议顶部的应用程序级协议。如何用http实现soap呢?
soap与http语法并没有重叠冲突的部分。http已经在各种类型的数据的传输方面制定了一整套规则,它应经能够传输图像,文本和声音。基于http的soap应用程序必须把传输中的数据指定为”text/xml”。

2.5.1 soap的http请求
可以通过各种http请求方法用http实现soap。soap技术标准只定义了一种与http的post请求相关联的绑定。
我们可以通过在http的header域里增加一个新的名为”SOAPAction”的属性来表明soap请求的目的。这个数据项的值是一个URI,但它不必是某种特定的格式,而且也不必是可解析的。这个出现在soap请求中的新数据域告诉我们三件事:
1)如果这个域出现并填上了值,它的值将告诉我们soap信息的目的。
2)如果这个域出现但没有填上值,则此信息的目的将由表示http请求的URI给出。
3)如果这个域没有出现意味着不指明该信息的目的。

2.5.2 soap的http响应
http上的soap遵守http中”status”代码的语法。如果返回的响应带有”2**”系类的状态码,就说明该信息被理解,接收,并处理了。如果在对请求的处理过程中出现了错误,soap应用程序必须返回一个http的”500  Internal Server Error”内部服务器出错响应。这个响应上的soap信息的信息体部分必须包含一个致命错误原因的SOAP Fault元素。

SOAP标准里有在http上实现soap的例子:
使用POST方法的SOAP HTTP请求:


2.6 soap在RPC中的应用
在xml得到标准化之后,许多跨平台项目开始使用它在各种平台上执行RPC(Remote Procedure call,
关于RPC的了解可以参考:
http://www.cnblogs.com/flyoung2008/archive/2011/11/12/2246282.html )。XML给了我们一种既容易阅读,又容易使用的包装材料。向另外一台机器发送一条信息来指定一个函数名及其相关参数对任何一个xml语法分析器来说都是件小事;而另外那台计算机会计算出返回值(如果有的话)并用xml把它传回去。soap只是把这种交谈的方法标准化了而已。
soap是一种信息化协议,而RPC不过是利用SOAP传递另外一种信息罢了。至于HTTP,它会把RPC调用映射到HTTP请求和响应方式的数据交换模型上去。在进行一次函数方法调用的时候,需要下面这些信息:
1.目标对象的URI。
2.能够对那个对象进行处理的有效方法的名字。
3.该方法的签名(可选)
4.该方法的参数。
5.信息头数据(可选)。

soap一般要通过协议绑定来把信息映射到URI去。在http里,请求里的URI会把执行RPC调用时需要用到的对象的名字告诉soap应用程序。如果协议绑定没有提供给出这种映射的办法,你可以用header元素提供点头绪。

2.6.1 RPC和SOAP消息体
soap信息体将承载方法调用内容和响应内容。soap技术标准对RPC的编码办法做了详细的规定。请求应该把函数方法调用纳入一个结构模型里去,而该结构访问子的名字必须与将要被调用的方法的名字一致。每个[in]和[in/out]参数必须写成彼此分开的元素,而他们又将被包含在函数方法的元素里。与方法一样,在给这些元素的访问子起名字时必须使用与之对应的调用参数的名字,他们的先后次序必须按方法签名的顺序安排。
与此相应的是对响应也有一套类似的规则。soap技术标准建议在给返回值起名字的时候都用”[method name]Response”。类似地,返回值需要对所有的[out]和[in/out]参数进行编码。如果有错误发生,响应里也应该包含它。

参考资料:
《SOAP:xml跨平台web service开发技术》 美.塞利

猜你喜欢

转载自zoroeye.iteye.com/blog/2048059