一、SOAP简介
如前所述,SOAP用XML作为数据编码格式。用XML作为数据编码格式并非SOAP的原创,实际上这是一种相当自然的选择。XML-RPC和ebXML也同样使用XML。要了解这方面的更多信息,请参见本文最后的“参考资源”。
请考虑下面的Java接口:
| Listing 1 public interface Hello { public String sayHelloTo(String name); } |
客户程序在调用sayHelloTo()方法时提供了一个名字,它希望从服务器接收到一则个性化的“Hello”信息。现在,假定RMI、CORBA和DCOM都不存在,开发者必须负责串行化方法调用,并把消息发送给远程机器。几乎所有的人都会说“这该使用XML”,我同意。因此,让我们先从对服务器的请求格式开始。假设要模拟sayHelloTo("John")调用,我打算发送的请求是:
| Listing 2 <?XML version="1.0"?> <Hello> <sayHelloTo> <name>John</name> </sayHelloTo> </Hello> |
在这里,我把接口的名字作为根结点。另外,我还把方法名字和参数名字都当作节点。接下来,我们要把这个请求发送给服务器。我们不创建自己的TCP/IP消息,而是使用HTTP。因此,下面的步骤应该是把请求封装成HTTP POST请求格式,然后把它发送给服务器。实际创建该HTTP POST请求的详细过程在本文后面介绍,现在,我们先假定它已经创建完毕。服务器接收到了这个请求,解码XML,然后再以XML格式向客户程序发送应答。假设应答内容如下:
| Listing 3 <?XML version="1.0"?> <Hello> <sayHelloToResponse> <message>Hello John, How are you?</message> </sayHelloToResponse> </Hello> |
根节点仍然是接口的名字Hello。但这一次,原来对应着方法的节点名字不再是sayHelloTo,而是方法的名字加上“Response”字符串。客户程序知道自己调用了哪一个方法,要找出被调用方法的返回值,它只需查看名字为方法名字加上“Response”字符串的元素。
以上就是SOAP的根本思路。Listing 4显示了同一请求用SOAP XML编码之后的结果:
| Listing 4 <SOAP-ENV:Envelope XMLns:SOAP-ENV="http://schemas.XMLsoap.org/soap/envelope/" XMLns:xsi="http://www.w3.org/1999/XMLSchema-instance" XMLns:xsd="http://www.w3.org/1999/XMLSchema"> <SOAP-ENV:Header> </SOAP-ENV:Header> <SOAP-ENV:Body> <ns1:sayHelloTo XMLns:ns1="Hello" SOAP-ENV:encodingStyle=" http://schemas.XMLsoap.org/soap/encoding/"> <name xsi:type="xsd:string">John</name> </ns1:sayHelloTo> </SOAP-ENV:Body> </SOAP-ENV:Envelope> |
看起来稍微复杂了一点,对吧?实际上,它和我们前面编写的请求类似,只是略微扩展了一些东西。首先,注意SOAP文档通过一个Envelope(根节点)、一个Header区、一个Body区,整洁地组织到一起。Header区用来封装那些与方法本身无直接关系的数据,提供环境方面的信息,比如事务ID和安全信息。Body区包含面向方法本身的信息。在Listing 2中,我们自己编写的XML只包含一个Body区。
第二,注意Listing 4大量地应用了XML名称空间。SOAP-ENV映射到名称空间http://schemas.XMLsoap.org/soap/envelope/,xsi映射到http://www.w3.org/1999/XMLSchema-instance,而xsd映射到http://www.w3.org/1999/XMLSchema。这三者是所有SOAP文档都拥有的标准名称空间。
最后,在Listing 4中,接口名称(即Hello)不再象在Listing 2中那样成为节点的名字;相反,它引用了一个名称空间nsl。另外,参数的类型信息也随同参数的值一起发送给了服务器。注意信封(Envelope)encodingStyle属性的值。这个属性值设置成了http://schemas.XMLsoap.org/soap/encoding/。这个值告诉服务器用来编码(即串行化)方法的编码方式;服务器需要这个信息,以便正确地解除方法的串行化。对于服务器来说,SOAP文档的自我描述能力是相当完善的。
对于上面的SOAP请求,服务器的应答如下:
| Listing 5 <SOAP-ENV:Envelope XMLns:SOAP-ENV="http://schemas.XMLsoap.org/soap/envelope/" XMLns:xsi="http://www.w3.org/1999/XMLSchema-nstance" XMLns:xsd="http://www.w3.org/1999/XMLSchema"> <SOAP-ENV:Body> <ns1:sayHelloToResponse XMLns:ns1="Hello" SOAP-ENV:encodingStyle="http://schemas.XMLsoap.org/soap/encoding/"> <return xsi:type="xsd:string">Hello John, How are you doing?</return> </ns1:sayHelloToResponse> </SOAP-ENV:Body> </SOAP-ENV:Envelope> |
Listing 5与Listing 4的请求消息类似。在上面的代码中,返回值(即个性化的“Hello”消息)包含在Body区。SOAP消息文档的格式非常灵活。例如,编码方式不固定,而是由客户程序指定。只要是客户程序和服务器都认可的编码方式,可以是任何合法的XML文档。
另外,分离调用环境信息意味着方法本身并不关心这类信息。在当前的市场上,主流应用服务器都遵从这一理念。早先,我曾经指出环境信息可以包含事务和安全方面的信息。事实上,环境可以涵盖几乎所有的东西。下面是一个SOAP消息头的例子,它带有一些事务方面的信息:
| Listing 6 <SOAP-ENV:Header> <t:Transaction XMLns:t="some-URI" SOAP-ENV:mustUnderstand="1"> 5 </t:Transaction> </SOAP-ENV:Header> |
名称空间t映射到了与特定应用有关的URI。这里的5表示的是该方法从属于其中的事务ID。注意SOAP信封mustUnderstand属性的应用。这个属性被设置成了1,它表示服务器要么理解并按照要求处理该事务请求,要么表示无法处理该请求;这是SOAP规范所要求的。
二、错误处理
使用SOAP并不意味着任何时候所有的请求都会获得成功。许多地方可能会出现差错。例如,服务器可能无法访问某个关键性的资源(比如数据库),因而无法顺利地处理请求。
让我们返回“Hello”实例,为它加上一个假想的约束,即“在星期二向别人说Hello不合法。”因此,星期二的时候,即使发送给服务器的请求是合法的,服务器也会把一个错误信息返回给客户端。应答内容将如下所示:
| Listing 7 <SOAP-ENV:Envelope XMLns:SOAP-ENV=" http://schemas.XMLsoap.org/soap/envelope/"> <SOAP-ENV:Body> <SOAP-ENV:Fault> <faultcode>SOAP-ENV:Server</faultcode> <faultstring>Server Error</faultstring> <detail> <e:myfaultdetails XMLns:e="Hello"> <message> Sorry, my silly constraint says that I cannot say hello on Tuesday. </message> <errorcode> 1001 </errorcode> </e:myfaultdetails> </detail> </SOAP-ENV:Fault> </SOAP-ENV:Body> </SOAP-ENV:Envelope> |
我们来分析一下http://schemas.XMLsoap.org/soap/envelope/名称空间定义的Fault元素。Fault元素总是Body元素的直接子元素,所有的SOAP服务器必须始终通过该元素报告所有错误情况。Fault元素必须包含faultcode和faultstring元素,不能有例外。faultcode是一个能够标识问题的代码;客户程序按照SOAP规范的要求利用faultcode进行算法处理。SOAP规范定义了一小组错误代码供用户使用。另一方面,faultstring是供人类阅读的错误信息。
Listing 7的代码还包含了一个detail元素。由于错误在处理SOAP消息的Body区时出现,detail元素必须出现。正如你将在本文后面看到的,如果错误在处理Header区时出现,detail元素不应出现。在Listing 7中,应用利用detail元素提供当前错误更详细、更自然的解释,即星期二不允许说Hello。SOAP还提供另外一个面向具体应用的错误代码,即半可选的faultfactor元素,但上面的错误信息中没有显示这个元素。之所以称这个元素是半可选的,是因为如果错误消息不是由请求最终处理点的服务器发送,即由一个中间服务器发送,则错误消息必须包含该元素。SOAP对faultcode元素不应出现的情形没有作任何规定。
在Listing 7中,错误起源于方法调用本身,处理该方法的应用导致了这个错误。现在,我们来看一下另一种类型的错误,这种错误由于服务器不能处理请求头信
更多内容请看PCdog.com--OSPF路由协议 计算机和网络技术基础知识 路由协议专题
