接上篇WebService原理浅析, SOAP编码有多种方式,我们在上一篇中使用的只是其中的一种,上一篇中我们介绍了WSDL的binding部分描述了WebService使用的协议及封装格式,其中封装格式是由样式( style )和编码(encode)控制的,本文将介绍样式和编码的组合是怎么影响SOAP封装,每种组合的优缺点以及使用建议。
样式( style )
WebService有两种通信样式( style ):
- document
- rpc
通过WSDL文件的binding部分可以判断WebService属于哪种样式(style),document示例如下:
......
<!-- document style示例 -->
<binding name="HelloWorldPortBinding" type="tns:HelloWorld">
<!-- style 属性表明使用的是哪种style -->
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
.....
rpc示例如下:
......
<!-- rpc style示例 -->
<binding name="HelloWorldPortBinding" type="tns:HelloWorld">
<!-- style 属性表明使用的是哪种style -->
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="rpc"/>
.....
编码( encode )
WebService有两种编码( encode )方式:
- encode
- literal
同样,通过WSDL文件的binding部分可以判断WebService属于哪种编码(encode),encode示例如下:
......
<binding name="HelloWorldPortBinding" type="tns:HelloWorld">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
<operation name="sayHelloWorld">
<soap:operation soapAction=""/>
<input>
<!-- use属性表明使用的编码格式-->
<soap:body use="encode"/>
</input>
......
literal示例如下:
......
<binding name="HelloWorldPortBinding" type="tns:HelloWorld">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
<operation name="sayHelloWorld">
<soap:operation soapAction=""/>
<input>
<!-- use属性表明使用的编码格式-->
<soap:body use="literal"/>
</input>
......
样式和编码组合对比
样式和编码有四种组合:
- rpc encode
- rpc literal
- document encode
- document literal
每种组合对应不同的SOAP协议格式,下文将使用上一篇( WebService原理浅析 )中的sayHelloWorld方法举例说明每种组合对应的协议格式,sayHelloWorld对应的Java签名如下:
public String sayHelloWorld(String arg0)
rpc encode
WSDL文件看起来如下:
......
<message name="sayHelloWorldRequest">
<part name="arg0" type="xsd:string"/>
</message>
......
<portType name="HelloWorld">
<operation name="sayHelloWorld">
<input message="sayHelloWorldRequest"/>
......
</operation>
</portType>
<binding ....../>
调用sayHelloWorld方法SOAP的协议封装看起来如下:
<soap:envelope>
<soap:body>
<sayHelloWorld>
<arg0 xsi:type="xsd:string">jack</arg0>
</sayHelloWorld>
</soap:body>
</soap:envelope>
优点:
- WSDL文件简单明了
- 消息里面有方法名sayHelloWorld和参数名arg0
缺点:
- 参数里面包含了类型信息,这样会降低传输性能,因为要多传输类型信息
- 无法验证SOAP表示的xml,元素sayHelloWorld和arg0根本就没有定义
rpc literal
WSDL文件看起来如下:
......
<message name="sayHelloWorldRequest">
<part name="arg0" type="xsd:string"/>
</message>
......
<portType name="HelloWorld">
<operation name="sayHelloWorld">
<input message="sayHelloWorldRequest"/>
......
</operation>
</portType>
<binding ....../>
调用sayHelloWorld方法SOAP的协议封装看起来如下:
<soap:envelope>
<soap:body>
<sayHelloWorld>
<arg0>jack</arg0>
</sayHelloWorld>
</soap:body>
</soap:envelope>
优点:
- WSDL文件简单明了
- 消息里面有方法名sayHelloWorld和参数名arg0
缺点:
- 无法验证SOAP表示的xml,元素sayHelloWorld和arg0没有定义。
document encoded
没有人使用这种风格,所以我们不做介绍。
document literal
WSDL文件看起来如下:
......
<types>
<schema>
<element name="arg0" type="xsd:string"/>
<schema>
</type>
<message name="sayHelloWorldRequest">
<part name="arg0" element="arg0"/>
</message>
......
<portType name="HelloWorld">
<operation name="sayHelloWorld">
<input message="sayHelloWorldRequest"/>
......
</operation>
</portType>
<binding ....../>
调用sayHelloWorld方法SOAP的协议封装看起来如下:
<soap:envelope>
<soap:body>
<arg0>jack</arg0>
</soap:body>
</soap:envelope>
优点:
- SOAP表示的xml可以验证,可以找到元素arg0的定义。
缺点:
- WSDL文件复杂了一些,因为定义了 一些新的xml元素arg0
- 消息里面没有方法名sayHelloWorld
document literal wrapped
综合四种组合的优缺点document literal wrapped应运而生, WSDL文件看起来如下:
......
<types>
<schema>
<element name="sayHelloWorld">
<complexType>
<element name="arg0" type="xsd:string"/>
</complexType>
</element>
<schema>
</types>
<message name="sayHelloWorldRequest">
<part name="parameters" element="sayHelloWorld"/>
</message>
......
<portType name="HelloWorld">
<operation name="sayHelloWorld">
<input message="sayHelloWorldRequest"/>
......
</operation>
</portType>
<binding ....../>
调用sayHelloWorld方法SOAP的协议封装看起来如下:
<soap:envelope>
<soap:body>
<sayHelloWorld>
<arg0>jack</arg0>
</sayHelloWorld>
</soap:body>
</soap:envelope>
优点:
- 包含了方法名和参数
- SOAP的xml文件可以验证,sayHelloWorld和arg0元素都已经定义了
缺点:
- WSDL文件变复杂了,增加了sayHelloWorld和arg0元素
应该选用哪种方式?
虽然document literal wrapped 会增加WSDL的复杂度,但是WSDL文件往往不需要人来处理,有现成的框架可以读取WSDL文件生成代码。所以document literal wrapped是最好的一种协议封装方式,我们应该优先使用这种方式,上一篇中便是使用了这种封装方式。
document literal wrapped虽好但是也有它不适用的场景,当WebService中有重载的方法名时,document literal wrapped 将不再适用,因为无法在xml中定义两个相同的方法名元素。
最后
style用来控制SOAP封装里面是否有方法名,document没有方法名,rpc有方法名,document wrapped也有方法名。
encode/literal用来控制SOAP封装的参数是否有数据类型,encode有数据类型,literal没有数据类型。
参考:
https://www.ibm.com/developerworks/library/ws-whichwsdl/index.html