Essential Web Services: SOAP, WSDL, UDDI

1. SOAP: 与 Web Service 无关

虽然SOAP可能是为了实现Web Service而被发明的,但实际上它可以被用在任何需要交换数据的场合(SOAP is an XML-based communication protocol and encoding format for inter-application communication)

  • SOAP本身是语义独立的,基本上只是一个信封,你可以往SOAP Header和SOAP Body里塞任何东西,也没有什么Header元素和Body元素是SOAP本身定义的,除了SOAP Fault

  • SOAP也是与数据交换方式,或者说传输方式无关的,HTTP,TCP...;

  • SOAP本身也是无状态,单向的;

让我们比较一下SOAP和现实生活中的信封:

  • 信封只是一个壳,但必不可少,其作用就是让接收者一看就知道是一封信,而不是一束花.(SOAP Envelop元素必不可少)

  • 信封对里面的信件内容一无所知,它也没规定里面必须是情书或者工资单. (SOAP 可以包裹任何内容)

  • 信件可以由信封包着,交给邮局送达,也可以由熟人顺路带过去. (SOAP 与传输方式无关,HTTP, JMS, SMTP...)

  • 信件接收者可以选择回信,也可以不回. (SOAP 是单向的)

是的,就像<<Web Service Security>>作者的比喻,SOAP是应用程序间的电子邮件

正是由于SOAP的这种灵活性,许多新的规范都在SOAP的基础上进行扩展和定制,像WS-Security, WS-Addressing等,无非就是定义了几个标准化的SOAP Header或SOAP Body元素

 

2. WSDL: 与 Runtime 无关

WSDL是Web Service的静态描述信息,主要是用于在客户程序的编码设计阶段告诉客户程序Web Service的信息,一旦客户程序在设计阶段获得了足够的信息,运行时根本不需要什么WSDL

或许某种情况下运行时需要WSDL的帮助吧,但我没有遇到过,如果你知道,请告诉我

portType其实就是Web服务的接口,但这个名字实在不直观,尤其对非英语国家的人来说,新版本的WSDL规范已经将portType改名为了 “Interface”

 

3. WSDL-SOAP Binding Style

就是所谓RPC与Document或者Wrapped,Literal与Encoding

先说Literal与Encoding

  • Literal就是不在SOAP消息中表明数据类型,而通过其它方式获知数据类型,这种方式是开发包相关的,没有什么标准;如<x>50</x>,单从SOAP消息,你无法判断50是数字还是字符串,而具体的类型可以在开发包将SOAP请求映射到具体的Service类时来确定并完成转换,对于返回值也一样,客户端可已通过SetReturnValueType(...)之类的方法告知开发包自己期待什么类型

  • Encoding就是在SOAP消息中携带类型信息,并且依据某种规则将数据编码传递,接收端可以根据类型信息和编码规则完成解码,获得原始数据;如<x xsi:type="xsd:string">50</x>

再看看RPC与Document

  • RPC就是按照类似函数调用时所需的信息来组装SOAP消息:操作名作为根元素,参数组成子元素,如:

<envelope><body><myMethod><x>5</x><y>8</y></myMethod></body></envelope> (RPC/Literal)

<envelope><body><myMethod><x type=string>5</x><y type=int>8</y></myMethod></body></envelope>  (RPC/Encoded)

 

  • Document就是将SOAP请求和响应,或者说输入输出定义为XML元素,有严格的Schema("document" style means the messages in and out of the service are exactly as they are describe by the XML Schema in the WSDL).如某个Web Service的WSDL片断:

<types>
    <schema>
        <element name="xElement" type="xsd:int"/>
    </schema>
</types>


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

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


则对应的SOAP消息如下:

<soap:envelope>
    <soap:body>
        <xElement>5</xElement>
    </soap:body>
</soap:envelope>

然而这种方式没有在SOAP消息中包含操作名,所以如果两个不同的操作具有相同的输入,开发包有可能无法决定把请求转发到哪个函数,为避免这种情况,开发包一般为每个操作的输入输出都产生具有唯一名称的Element,不管它们是否内容相同;或者作为开发者,你可以选择 Wrapped 风格

 

  • Wrapped 风格就是定义与操作同名的Element,将参数作为 Child Element;这样操作名又重新回到了SOAP消息中,如WSDL片断:

<types>
    <schema>       
        <element name="myMethod"/>
            <complexType>
                <sequence>
                    <element name="x" type="xsd:int"/>
                </sequence>
            </complexType>
        </element>

    </schema>
</types>
<message name="myMethodRequest">
    <part name="parameters" element="myMethod"/>
</message>
<message name="empty"/>

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


对应的SOAP消息:

<soap:envelope>
    <soap:body>
        <myMethod>  <x>5</x>   </myMethod>
    </soap:body>
</soap:envelope>

这种方式也具有明显的弱点:无法方便的处理重载,因为XML Schema不允许定义相同名称的元素;这样,即使你的后台编程语言支持函数重载,你也应该尽量避免使用

 

Document services and wrapped services are similar in that neither uses the SOAP encoding for data; it's just plain old XML schema.

 

4. UDDI:与 WSDL 无关

虽然都是描述Web Service的,但UDDI与WSDL各司其责;事实上,UDDI野心太大,定义了很多社会性的Attribute,而不局限于技术性的Web服务,如人工电话服务信息和传真服务信息都可以注册到UDDI中,描述性的东西很多(descriptive information )一些overviewURL 也都推荐指向文档,关于这点,参照目前UDDI的应用情况,我认为UDDI是过度设计了

UDDI注册表其实是一堆元数据的集合,元元数据...,元数据用tModel来表达,可以有不同的分类,通过tModel key来引用;当你试图用字符串表达什么东西时,你最好看看是否已经有了对应的tModel,有的话你就需要用对该tModel的引用来代替字符串,如在UDDI中表达一个Web Service的PortType时,你不应该在某处用字符串“PortType”来表明这是一个Port Type,你应该引用预定义的PortType tModel来表明:

<tModel tModelKey="uuid:e8cf1163-8234-4b35-865f-94a7322e40c3" >

    <name> StockQuotePortType</name>

    <overviewDoc> <overviewURL> http://location/sample.wsdl <overviewURL> <overviewDoc>

    <categoryBag>

         <keyedReference tModelKey="uuid:d01987d1-ab2e-3013-9be2-2a66eb99d824"  keyName="namespace" keyValue="http://example.com/stockquote/" />

         <keyedReference tModelKey="uuid:6e090afa-33e5-36eb-81b7-1ca18373f457"  keyName="WSDL type" keyValue="portType" />

    </categoryBag>

</tModel>

Web Service与UDDI的关系类似于COM组件服务与Windows注册表的关系,其实它们可以看作是同一个概念的不同发展阶段或不同实现

而UDDI直观的比喻可以是图书馆卡片索引,在我上中学的时候,图书馆没有计算机供读者查询图书信息,只有一柜一柜一橱一橱的索引卡片,记录了图书信息,如作者出版社等,当然最重要的是它在书库里的位置,第几排第几格

分类体系在UDDI中占很大比重,不同的Category如传输协议,命名空间,WSDL Type等,每一个Entity或tModel都可以具有多个分类属性,比如上面的StockQuotePortType tModel,按名称空间来分,它属于http://example.com/stockquote/,按WSDL Type来分,它属于portType;BindingTemplate Entity还具有传输协议的分类,值可以是HTTP或SMTP之类

分类体系在现实生活中随处可见,比如说同一个人,按性别分是mm,按婚否分是未婚,按政治面貌分是刁民;图书馆的索引卡片上也随处可见,按出版社分是三联,按题材分是小说,按风格分是后现代等等

 

5. UDDI:与WSDL 有关

毕竟都是描述WebService的,还是有部分内容有关系的,于是有了WSDL到UDDI的映射,这样某些工具就可以自动将WebService注册到UDDI中

大体上就是<portType>和<binding>作为tModel映射到UDDI中,<service>映射为<businessService>, <port>映射为<bindingTemplate>

 

6. JAX-RPC: 首先是Java,其次才是RPC

虽然JAX-RPC不厌其烦的表达自己支持但不依赖SOAP的特性,但支持SOAP之外的消息交换机制究竟目前有没有具体应用,我不知道,每个开发包也从框架上支持任意的消息交换机制,但我见过的应用都是把它们作为SOAP引擎,如果你知道SOAP之外的消息交换机制的具体应用,请告诉我

 

你可能感兴趣的:(Essential Web Services: SOAP, WSDL, UDDI)