2008年10月14日星期二

SOAP中 RPC/encoded, RPC/literal, document/literal 之间区别

最近看了一个IBM的文章讲SOAP四种消息方式的差别

RPC是面向调用的,所以要求在payload中包含operation名字
而document方式是不包含operation名字的,payload里直接就是part

encoded包含part的类型信息,比如xsi:type="xsd:int"
literal是不包含part的类型信息但是通过引用schema里的元素也可以容易的通过schema验证

RPC/encoded
WSDL:
<message name="myMethodRequest">
<part name="x" type="xsd:int"/>
<part name="y" type="xsd:float"/>
</message>
<message name="empty"/>

<portType name="PT">
<operation name="myMethod">
<input message="myMethodRequest"/>
<output message="empty"/>
</operation>
</portType>

Payload on wire:
<myMethod>
<x xsi:type="xsd:int">5</x>
<y xsi:type="xsd:float">5.0</y>
</myMethod>
优点:
服务端通过payload的顶层元素operation-name就可以分发请求到底层实现类,不需要根据myMethod内的几个part的类型来找到到底调用的哪一个operation
缺点:
xsi:type="xsd:int"这种太长,也没必要,性能下降
验证麻烦,x, y是单独通过schema type验证,而myMethod不属于schema,属于WSDL定义。
不兼容WS-I,所以互操作性有问题


RPC/Literal
WSDL: 和RPC/encoded一样

Payload on wire:
<myMethod>
<x>5</x>
<y>5.0</y>
</myMethod>
优点:
服务端通过payload的顶层元素operation-name就可以分发请求到底层实现类,和RPC/encoded一样
type encoding 没有了,性能能上升
RPC/literal is WS-I compliant.
缺点:
不容易验证message因为不包含x和y的类型信息,myMethod也不是schema定义的。


Document/encoded
Nobody follows this style. It is not WS-I compliant. So let's move on.


Document/Literal
WSDL:多了包含schema的types元素
<types>
<schema>
<element name="xElement" type="xsd:int"/>
<element name="yElement" type="xsd:float"/>
</schema>
</types>

<message name="myMethodRequest">
<part name="x" element="xElement"/>
<part name="y" element="yElement"/>
</message>
<message name="empty"/>

<portType name="PT">
<operation name="myMethod">
<input message="myMethodRequest"/>
<output message="empty"/>
</operation>
</portType>

Payload on wire:
<xElement>5</xElement>
<yElement>5.0</yElement>

优点:
没有type信息,消息简短,传输性能好
所有payload内的内容都可以通过schema校验(xElement是引用types里的schema)
WS-I部分兼容(只有一个元素的时候才兼容)
缺点:
WSDL复杂,包含了太多types
operation name没有了,分发比较复杂(后面解释soapAction)
WS-I要求soap:body内只有一个元素,而这里有了两个,所以有时候不兼容WS-I

其中在HTTP头里加入soapAction可以解决分发问题,SOAP 1.1规范里说:The SOAPAction HTTP request header field can be used to indicate the intent of the SOAP HTTP request. The value is a URI identifying the intent
那么intent是什么呢?你需要在WSDL定义operation的时候给operation指定soapAction,这相当于一个operation的key或者id
当document/literal的时候,如果有两个operation用了同样的参数(类似于方法重载), 那么服务端无法区分是调用了哪个operation
这种情况下,必须要包含soapActiont头来指明到底哪个operation被调用。当然soapAction不要太长,否则还不如包含type的效率高
注意:在SOAP 1.2协议中,soapActionb变成了action。


Document/literal wrapped pattern
从这看出来,就算是document/literal虽然可以校验message但是没有了operation,RPC/literal相反,有operation但是校验message比较麻烦
如果两点都能满足的话多好?恩,现在事实上从微软开始,很多人逐渐采用了document/literal wrapped pattern来解决这个问题.

WSDL:
<types>
<schema>
<element name="myMethodRequest">
<complexType>
<sequence>
<element name="x" type="xsd:int"/>
<element name="y" type="xsd:float"/>
</sequence>
</complexType>
</element>
<element name="myMethodResponse">
<complexType/>
</element>
</schema>
</types>
<message name="myMethodRequest">
<part name="parameters" element="myMethodRequest"/>
</message>
<message name="myMethodResponse">
<part name="parameters" element="myMethodResponse"/>
</message>

<portType name="PT">
<operation name="myMethod">
<input message="myMethodRequest"/>
<output message="myMethodResponse"/>
</operation>
</portType>

Payload on wire
<myMethod>
<x>5</x>
<y>5.0</y>
</myMethod>
这么乍一看,payload和RPC/literal一样的,没有什么变化,其实不然。在RPC/literal中myMethod就是operation。但是在docment/literal wrapped中,myMethod是wrapper的名字,这个可以通过payload中唯一的input message得到operation,这样operation也可以得到了。

对于document/literal wrapped方式,有几个特点:
对于每一个operation, input message只有一个
part不是primitive类型,是一个complex element
wrapper和operation名字一样
wrapper没有任何atrribute

优点:
没有type encoding,消息短小,效率高
payload所有元素都可以有对应的schema校验(从根元素myMethod开始)
soap body里的wrapper就是operation,所以容易分发
wrapper增加的约束使得document/literal方式的payload只有一个元素(myMethod),满足了WS-I
缺点:
WSDL太长
本身只是一个style,不是标准或者规范

没有评论: