【编者按】网学网ASP.net频道为大家收集整理了“简单对象协议(SOAP)简介“提供大家参考,希望对大家有所帮助!
简单对象访问协议-CNXML标准教程 <br>
2000-9-25 作者:何杭军<br>
<br>
"SOAP是在非集中、分布环境中交换信息的轻量级协议。它是基于XML的协议,包括三个部分: 封套(envelope)定义了消息内容和处理的框架、一套编码规则用来表达应用定义数据类型的实例以及表达远程过程调用和响应的协定。"<br>
——SOAP 1.1规范<br>
<br>
第一节 SOAP简介<br>
<br>
SOAP(Simple Object Access Protocal,简单对象访问协议) 技术有助于实现大量异构程序和平台之间的互操作性,从而使存在的应用能够被广泛的用户所访问。SOAP是把成熟的基于HTTP的WEB技术与XML的灵活性和可扩展性组合在了一起。<br>
<br>
SOAP的一个主要目标是使存在的应用能被更广泛的用户所使用。为了实现这个目的,没有任何SOAP API或SOAP 对象请求代理(SOAP ORB),SOAP是假设你将使用尽可能多的存在的技术。几个主要的CORBA厂商已经承诺在他们的ORB产品中支持SOAP协议。微软也承诺在将来的COM版本中支持SOAP。DevelopMentor已经开发了参考实现,它使得在任何平台上的任何Java或Perl程序员都可以使用SOAP。而且IBM和Sun也陆续支持了SOAP协议,和MS合作共同开发SOAP规范和应用。目前SOAP已经成为了W3C和IETF的参考标准之一。<br>
<br>
SOAP的指导理念是“它是第一个没有发明任何新技术的技术”。它采用了已经广泛使用的两个协议:HTTP和XML。HTTP用于实现SOAP的RPC风格的传输,而XML是它的编码模式。采用几行代码和一个XML解析器,HTTP服务器(如MS的IIS或Apache)立刻成为了SOAP的ORBs。 因为目前超过一半的Web服务器采用IIS或Apache, SOAP将会从这两个产品的广泛而可靠的使用中获取利益。这并不意味着所有的SOAP请求必须通过Web服务器来路由,传统的Web 服务器只是分派SOAP请求的一种方式。因此Web服务如IIS或Apache对建立SOAP性能的应用是充分的,但决不是必要的。<br>
<br>
SOAP把XML的使用代码化为请求和响应参数编码模式,并用HTTP作传输。这似乎有点抽象。具体地讲,一个SOAP方法可以简单地看作遵循SOAP编码规则的HTTP请求和响应。一个SOAP终端则可以看作一个基于HTTP的URL,它用来识别方法调用的目标。象CORBA/IIOP一样,SOAP不需要具体的对象被绑定到一个给定的终端,而是由具体实现程序来决定怎样把对象终端标识符映射到服务器端的对象。<br>
<br>
SOAP请求是一个HTTP POST请求。SOAP请求的content-type必须用text/xml。而且它必须包含一个请求-URI。服务器怎样解释这个请求-URI是与实现相关的,但是许多实现中可能用它来映射到一个类或者一个对象。一个SOAP请求也必须用SOAPMethodName HTTP头来指明将被调用的方法。简单地讲,SOAPMethodName头是被URI指定范围的应用相关的方法名,它是用#符作为分隔符将方法名与URI分割开:<br>
<br>
SOAPMethodName: urn:strings-com:IString#reverse <br>
<br>
这个头表明方法名是reverse,范围URI是urn:strings-com:Istring。 在SOAP中,规定方法名范围的名域URI在功能上等同于在DCOM 或 IIOP中规定方法名范围的接口ID。<br>
<br>
简单的说,一个SOAP请求的HTTP体是一个XML文档,它包含方法中[in]和[in,out]参数的值。这些值被编码成为一个显著的调用元素的子元素,这个调用元素具有SOAPMethodName HTTP头的方法名和名域URI。调用元素必须出现在标准的SOAP <Envelope>和<Body>元素内(后面会更多讨论这两个元素)。下面是一个最简单的SOAP方法请求:<br>
<br>
POST /string_server/Object17 HTTP/1.1<br>
Host: 209.110.197.2<br>
Content-Type: text/xml<br>
Content-Length: 152<br>
SOAPMethodName: urn:strings-com:IString#reverse <br>
<Envelope><br>
<Body><br>
<m:reverse xmlns:m=''''urn:strings-com:IString''''><br>
<theString>Hello, World</theString><br>
</m:reverse><br>
</Body><br>
</Envelope><br>
SOAPMethodName头必须与<Body>下的第一个子元素相匹配,否则调用将被拒绝。这允许防火墙管理员在不解析XML的情况下有效地过滤对一个具体方法的调用。<br>
<br>
SOAP响应的格式类似于请求格式。响应体包含方法的[out]和 [in,out]参数,这个方法被编码为一个显著的响应元素的子元素。这个元素的名字与请求的调用元素的名字相同,但以Response后缀来连接。下面是对前面的SOAP请求的SOAP响应:<br>
<br>
200 OK Content-Type: text/xml <br>
Content-Length: 162 <br>
<Envelope> <br>
<Body> <br>
<m:reverseResponse xmlns:m=''''urn:strings-com:IString''''><br>
<result>dlroW ,olleH</result><br>
</m:reverseResponse><br>
</Body><br>
</Envelope> <br>
这里响应元素被命名为reverseResponse,它是方法名紧跟Response后缀。要注意的是这里是没有SOAPMethodName HTTP头的。这个头只在请求消息中需要,在响应消息中并不需要。<br>
<br>
第二节 SOAP体的核心<br>
<br>
SOAP的XML特性是为把数据类型的实例序列化成XML的编码模式。为了达到这个目的,SOAP不要求使用传统的RPC风格的代理。而是一个SOAP方法调用包含至少两个数据类型:请求和响应。考虑这下面个COM IDL代码:<br>
<br>
<br>
[ uuid(DEADF00D-BEAD-BEAD-BEAD-BAABAABAABAA) ]<br>
interface IBank : IUnknown {<br>
HRESULT withdraw([in] long account, <br>
[out] float *newBalance,<br>
[in, out] float *amount<br>
[out, retval] VARIANT_BOOL *overdrawn);<br>
}<br>
在任何RPC协议下,account和amount参数的值将出现在请求消息中,newBalance、overdrawn参数的值,还有amount参数的更新值将出现在响应消息中。<br>
<br>
SOAP把方法请求和方法响应提升到了一流状态。在SOAP中,请求和响应实际上类型的实例。为了理解一个方法比如IBank::withdraw怎样映射一个SOAP请求和响应类型,考虑下列的数据类型:<br>
<br>
struct withdraw {<br>
long account;<br>
float amount;<br>
};<br>
<br>
这时所有的请求参数被打包成为单一的结构类型。同样下面的数据表示打包所有响应参数到单一的数据类型。 <br>
<br>
struct withdrawResponse {<br>
float newBalance;<br>
float amount;<br>
VARIANT_BOOL overdrawn;<br>
};<br>
再给出下面的简单的Visual Basic程序,它使用了以前定义的Ibank接口:<br>
<br>
Dim bank as IBank<br>
Dim amount as Single<br>
Dim newBal as Single<br>
Dim overdrawn as Boolean<br>
amount = 100<br>
Set bank = GetObject("soap:http://bofsoap.com/am")<br>
overdrawn = bank.withdraw(3512, amount, newBal)<br>
<br>
<br>
这里,在发送请求消息之前,参数被序列化成为一个请求对象。同样被响应消息接收到的响应对象被反序列化为参数。一个类似的转变同样发生在调用的服务器端。<br>
<br>
当通过SOAP调用方法时,请求对象和响应对象被序列化成一种已知的格式。每个SOAP体是一个XML文档,它具有一个显著的称为<Envelope>的根元素。标记名<Envelope>由SOAP URI (urn:schemas-xmlsoap-org:soap.v1)来划定范围,所有SOAP专用的元素和属性都是由这个URI来划定范围的。SOAP Envelope包含一个可选的<Header>元素,紧跟一个必须的<Body>元素。<Body>元素也有一个显著的根元素,它或者是一个请求对象或者是一个响应对象。下面是一个IBank::withdraw请求的编码:<br>
<br>
<soap:Envelope xmlns:soap=''''urn:schemas-xmlsoap-org:soap.v1''''><br>
<soap:Body><br>
<IBank:withdraw xmlns:IBank=''''urn:uuid:DEADF00D-BEAD-BEAD-BEAD-BAABAABAABAA''''><br>
<account>3512</account><br>
<amount>100</amount><br>
</IBank:withdraw><br>
</soap:Body><br>
</soap:Envelope><br>
下列响应消息被编码为: <br>
<soap:Envelope xmlns:soap=''''urn:schemas-xmlsoap-org:soap.v1''''><br>
<soap:Body><br>
<IBank:withdrawResponse xmlns:IBank=''''urn:uuid:DEADF00D-BEAD-BEAD-BEAD-BAABAABAABAA''''><br>
<newBalance>0</newBalance><br>
<amount>5</amount> <br>
<overdrawn>true</overdrawn><br>
</IBank:withdrawResponse><br>
</soap:Body><br>
</soap:Envelope><br>
注意[in, out]参数出现在两个消息中。在检查了请求和响应对象的格式后,你可能已经注意到序列化格式通常是: <br>
<br>
<t:typename xmlns:t=''''namespaceuri''''><br>
<fieldname1>field1value</fieldname1><br>
<fieldname2>field2value</fieldname2><br>
......<br>
</t:typename> <br>
在请求的情况下,类型是隐式的C风格的结构,它由对应方法中的[in]和[in, out]参数组成。对响应来说,类型也是隐式的C风格的结构,它由对应方法中的[out]和[in, out]参数组成。这种每个域对应一个子元素的风格有时被称为元素正规格式(ENF)。一般情况下,SOAP只用XML特性来传达描述包含在元素内容中信息的注释。<br>
<br>
象DCOM和IIOP一样,SOAP支持协议头扩展。SOAP用可选的<Header>元素来传载被协议扩展所使用的信息。如果客户端的SOAP软件包含要发送头信息,原始的请求将可能如图9所示。在这种情况下命名causality的头将与请求一起序列化。收到请求后,服务器端软件能查看头的名域URI,并处理它识别出的头扩展。这个头扩展被http://comstuff.com URI识别,并期待一个如下的对象:<br>
<br>
struct causality { <br>
UUID id; <br>
}; <br>
在这种情况下的请求,如果头元素的URI不能被识别,头元素可以被安全地忽略。<br>
<br>
但你不能安全的忽略所有的SOAP体中的头元素。如果一个特定的SOAP头对正确处理消息是很关键的,这个头元素能被用SOAP属性mustUnderstand=’true’标记为必须的。这个属性告诉接收者头元素必须被识别并被处理以确保正确的使用。为了强迫前面causality头成为一个必须的头,消息将被写成如下形式:<br>
<br>
<soap:Envelope xmlns:soap=''''urn:schemas-xmlsoap-org:soap.v1''''><br>
<soap:Header><br>
<causality soap:mustUnderstand=''''true''''xmlns="http://comstuff.com"><br>
<id>362099cc-aa46-bae2-5110-99aac9823bff</id><br>
</causality> <br>
</soap:Header><br>
</soap:Envelope><br>
SOAP软件遇到不能识别必须的头元素情况时,必须拒绝这个消息并出示一个错误。如果服务器在一个SOAP请求中发现一个不能识别的必须的头元素,它必须返回一个错误响应并且不发送任何调用到目标对象。如果客户端在一个SOAP请求中发现一个不能识别出的必须的头元素,它必须向调用者返回一个运行时错误。在COM情况下,这将映射为一个明显的HRESULT。<br>
<br>
<br>
第三节 SOAP数据类型<br>
<br>
在SOAP消息中,每个元素可能是一个SOAP结构元素、根元素、存取元素或一个独立的元素。在SOAP中,soap:Envelope、soap:Body和soap:Header是唯一的组成元素。它们的基本关系由下列XML Schema所描述: <br>
<br>
<schema targetNamespace=''''urn:schemas-xmlsoap-org:soap.v1''''><br>
<element name=''''Envelope''''><br>
<type><br>
<element name=''''Header'''' type=''''Header'''' minOccurs=''''0'''' /><br>
<element name=''''Body'''' type=''''Body''''minOccurs=''''1'''' /><br>
</type><br>
</element><br>
</schema><br>
在SOAP元素的四种类型中,除了结构元素外都被用作表达类型的实例或对一个类型实例的引用。<br>
<br>
根元素是显著的元素,它是soap:Body 或是 soap:Header的直接的子元素。其中soap: Body只有一个根元素,它表达调用、响应或错误对象。这个根元素必须是soap:Body的第一个子元素,它的标记名和域名URI必须与HTTP SOAPMethodName头或在错误消息情况下的soap:Fault相对应。而soap:Header元素有多个根元素,与消息相联系的每个头扩展对应一个。这些根元素必须是soap:Header的直接子元素,它们的标记名和名域URI表示当前存在扩展数据的类型。<br>