一般信息

SOAP 是简单对象访问协议Simple Object Access Protocol )的首字母缩写,它定义了一种协议,用于通过远程过程调用(RPC)与其他 SOAP 服务或客户端交换数据。它有两个版本:

SOAP 1.2 废弃了 SOAP 1.1,因此建议尽可能使用 SOAP 1.2。

它通常建立在 HTTP / S 之上,很少在 SMTP 或 FTP 上构建,尽管它会根据协议支持它。尽管 HTTP 通常用作底层传输协议,但 SOAP 仅使用它的有限子集。对于发送请求,它几乎完全依赖于 HTTP 的 POST 操作。从 1.2 开始,GET 调用在理论上是可行的,尽管文档必须作为 URI 参数传递,因此可能超过大约 3000 个字符边界,这被大多数框架拒绝。此外,安全相关的设置通常在特殊的 SOAP 标头中定义。

虽然 SOAP 和 REST 被称为 Web 服务,但它们本质上是非常不同的。一些框架区分 WS(用于基于 SOAP 的服务)和 RS(用于基于 REST 的服务)。

下表简要概述了两种 Web 服务类型之间的差异。

方面 肥皂 休息
标准 SOAPWSDL 没有标准,只是一种建筑风格
资源寻址 间接通过 SOAP 操作 通过唯一资源标识符(URI)
错误处理 SOAP 错误消息 HTTP 错误响应代码和可选的响应主体
数据表示 XML HTTP 中所有可用的编码
HTTP 使用情况 作为传输协议 映射在 HTTP 方法上的资源操作(CRUD)(GET,POST,PUT,DELETE,…)
交易支持 通过 SOAP 标头 通过将事务建模为资源
状态 有状态(SOAP 操作是应用程序的一部分) 无国籍(独立请求)
服务发现 UDDI / WSDL 实际上没有; API 的 Start-URI 应返回子 API 列表
方法 在 SOAP 体内 HTTP 方法
方法参数 由 WSDL 中的 XML 模式定义 通过 URI 中的 HTTP 标头或路径/查询或 Matrix 参数
状态转换 很难确定不直接基于数据 下一个 URI 调用
缓存支持 缓存通常不需要, HTTP 定义的简单

肥皂

SOAP 请求由 SOAP 信封组成,该信封必须包含一个 body 元素,并且可以包含一个可选的 header 元素。header 元素用于将某些配置传递给服务,例如 WS-Security 可以定义消息是加密的,或者 WS-Coordination / WS-Transaction 可以定义消息必须在事务中执行。

一个简单的 SOAP 1.2 请求通过 HTTP 添加两个值可能如下所示:

POST /calculator HTTP/1.1
Host: http://example.org
Content-Type: application/soap+xml; charset=utf-8
Content-Length: 224

<?xml version="1.0"?>
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope">
 <env:Body>
  <m:AddValues xmlns:m="http://example.org/calculator">
   <m:FirstValue>1</m:FirstValue>
   <m:SecondValue>2</m:SecondValue>
  </m:AddValues>
 </env:Body>
</env:Envelope>

对上述示例请求的响应可能如下所示

HTTP/1.1 200 OK
Content-Type: application/soap+xml; charset=utf-8
Content-Length: 329

<?xml version="1.0"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"
               soap:encodingStyle="http://www.w3.org/2003/05/soap-encoding">
 <soap:Body xmlns:m="http://www.example.org/calculator">
  <m:AddValuesResponse>
   <m:Result>3</m:Result>
  </m:AddValuesResponse>
 </soap:Body>
</soap:Envelope>

上面的例子定义了一个请求,它使用两个参数调用 AddValues 方法,FirstValue 设置为 1SecondValue 设置为 2。该请求导致在远程 SOAP 服务器上执行此方法,该服务器计算了 3 的值作为结果,该值封装在单独的响应元素中,按照惯例,该元素通常是调用的方法名称加上尾随 Response 字符串,因此任何人都是检查响应可以得出结论,这是之前的 AddValue 方法调用的响应。

SOAP 1.1 和 1.2 之间的差异

只要协议支持绑定框架,SOAP 1.2 就允许其他传输协议,然后是 HTTP。

SOAP 1.1 基于 XML 1.0,而 1.2 基于 XML Infoset,它允许使用其他序列化程序将 SOAP 消息序列化,然后使用 SOAP 1.1 使用的默认 XML 1.0 序列化程序。这允许 ie 将消息序列化为二进制消息,从而防止消息的 XML 性质的一些开销。除此之外,可以通过数据绑定来确定所使用的底层协议的序列化机制。

通过定义比其前身更具体的处理模型,消除了许多解释的可能性,SOAP 1.2 也促进了互操作性方面。SOAP with Attachment API(SAAJ) 允许对 SOAP 1.1 和 1.2 消息进行操作,它帮助许多框架实现者处理和创建消息。

W3C 发布了 SOAP 1.1 和 1.2 之间主要变化的简短概述

Web 服务互操作性

Web 服务互操作性(也称为 WS-I) 是由一些知名企业(如 IBM,Microsoft,Oracle 和 HP )管理的互操作性指南,仅举几例。这些指南建议在 SOAP 主体中仅使用一个单独的根元素,即使 SOAP 允许在主体内包含多个元素。

WS-I 由

  • WS-I Basic Profile 又名 WSI-BP
  • WS-I 基本安全配置文件
  • 简单的肥皂结合配置文件

WSI-BP 提供 4 个不同版本 v1.0(2004)v1.1(2006)v1.2(2010)v2.0(2010) 并定义了核心 Web 服务规范(如 SOAP,WSDL )的互操作性指南和 UDDI。通过使用 Web 服务描述语言(WSDL),SOAP 服务可以在与其他端点的内聚集中描述其支持的操作和方法。WSI-BP 利用 WSDL 定义一个较窄的集合,然后完整的 WSDL 或 SOAP 模式将定义,从而消除规范本身内部的一些歧义,从而提高端点之间的互操作性。

WSDL

为了宣传可用的 SOAP 操作,它们的参数以及要调用给客户端的相应端点,使用另一个基于 XML 的文档,简称为 Web Services Description Language 或 WSDL。

WSDL 描述了服务端点,SOAP 消息与操作的绑定,操作的接口以及它们对客户端的类型。与 SOAP 类似,WSDL 有 2 个版本可供选择,它们的语法略有不同,尽管它们对客户端表达的语义几乎相同。

WSDL 1.1

WSDL 1.1 描述包含 servicebindingportTypemessage 部分。它可以进一步导入或定义 WSDL 文件中的模式,这可以从对应于上面显示的计算器示例的示例 WSDL 文件中看到:

<wsdl:definitions xmlns:xs="http://www.w3.org/2001/XMLSchema"
                  xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
                  xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
                  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
                  xmlns:calc="http://example.org/calculator"
                  xmlns:tns="http://example.org/calculatorService"
                  targetNamespace="http://example.org/calculatorService">

    <!--
      Abstract type definitions
    -->

    <wsdl:types>
        <!--
        <xs:schema>
            <xs:import namespace="http://example.org/calculator" schemaLocation="calc/calculator.xsd" />
        </xs:schema>
        -->
        <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
                   xmlns:tns="http://example.org/calculator"
                   targetNamespace="http://example.org/calculator"
                   elementFormDefault="qualified"
                   attributeFormDefault="qualified">

            <xs:element name="AddValuesRequest" type="tns:AddValuesType" />
            <xs:element name="AddValuesResponse" type="tns:AddValuesResponseType" />

            <xs:complexType name="AddValuesType">
                <xs:sequence>
                    <xs:element name="FirstValue" type="xs:int" minOccurs="1" maxOccurs="1" />
                    <xs:element name="SecondValue" type="xs:int" minOccurs="1" maxOccurs="1" />
                </xs:sequence>
            </xs:complexType>

            <xs:complexType name="AddValuesResponseType">
                <xs:sequence minOccurs="1" maxOccurs="1">
                    <xs:element name="Result" type="xs:int" />
                </xs:sequence>
            </xs:complexType>

            <xs:attribute name="Timestamp" type="xs:dateTime" />
            <xs:element name="CalculationFailure">
                <xs:complexType>
                    <xs:sequence>
                        <xs:element name="ErrorCode" type="xs:int" />
                        <xs:element name="Reason" type="xs:string" />
                    </xs:sequence>
                    <xs:attribute ref="tns:Timestamp" use="required" />
                </xs:complexType>
            </xs:element>

        </xs:schema>
    </wsdl:types>

    <!--
        Abstract message definitions
    -->

    <wsdl:message name="AddValuesRequest">
        <wsdl:part name="in" element="calc:AddValuesRequest" />
    </wsdl:message>
    <wsdl:message name="AddValuesResponse">
        <wsdl:part name="out" element="calc:AddValuesResponse" />
    </wsdl:message>
    <wsdl:message name="CalculationFault">
        <wsdl:part name="fault" element="calc:CalculationFailure" />
    </wsdl:message>

    <!--
        Abstract portType / interface definition
    -->

    <wsdl:portType name="CalculatorEndpoint">
        <wsdl:operation name="AddValues">
            <wsdl:documentation>Adds up passed values and returns the result</wsdl:documentation>
            <wsdl:input message="tns:AddValuesRequest" />
            <wsdl:output message="tns:AddValuesResponse" />
            <wsdl:fault name="CalculationFault" message="tns:CalculationFault" />
        </wsdl:operation>
    </wsdl:portType>

    <!--
      Concrete binding definition
    -->

    <wsdl:binding name="CalculatorBinding" type="tns:CalculatorEndpoint">
        <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
        <wsdl:operation name="AddValues">
            <soap:operation soapAction="http://example.org/calculator/AddValuesMessage" />
            <wsdl:input>
                <soap:body parts="in" use="literal" />
            </wsdl:input>
            <wsdl:output>
                <soap:body parts="out" use="literal" />
            </wsdl:output>
            <wsdl:fault name="CalculationFault">
                <soap:fault name="CalculationFault" use="literal" />
            </wsdl:fault>
        </wsdl:operation>
    </wsdl:binding>

    <!--
        Concrete service definition
    -->

    <wsdl:service name="CalculatorService">
        <wsdl:port name="CalculatorServicePort" binding="tns:CalculatorBinding">
            <soap:address location="http://localhost:8080/services/calculator" />
        </wsdl:port>
    </wsdl:service>

</wsdl:definitions>

service 部分定义服务将侦听传入请求的具体端点。binding 部分将操作绑定到具体样式,并定义服务器期望或客户端可以期望的消息格式。

抽象部分由 portType 块组成,该块定义了服务提供的操作以及交换的消息。消息在其 on 块中指定,并链接到参数和返回值为实例的模式类型。消息可以声明参数或返回值为 inoutinout。虽然前两个很容易掌握,后者模仿参考传递的参数的行为。由于某些语言不支持 pass-by-ref,因此通常会通过某些处理程序模拟此效果。

WSDL 2.0

可以在 WSDL 2.0 中描述相同的计算器,如下所示:

<?xml version="1.0" encoding="utf-8" ?>
<wsdl:description xmlns:xs="http://www.w3.org/2001/XMLSchema"
                  xmlns:wsdl="http://www.w3.org/ns/wsdl"
                  xmlns:soap="http://www.w3.org/ns/wsdl/soap"
                  xmlns:calc="http://example.org/calculator"
                  xmlns:tns="http://example.org/calculatorService"
                  targetNamespace="http://example.org/calculatorService">

    <!--
      Abstract type definitions
    -->

    <wsdl:types>
        <!--
        <xs:schema>
            <xs:import namespace="http://example.org/calculator" schemaLocation="calc/calculator.xsd" />
        </xs:schema>
        -->
        <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
                   xmlns:tns="http://example.org/calculator"
                   targetNamespace="http://example.org/calculator"
                   elementFormDefault="qualified"
                   attributeFormDefault="qualified">

            <xs:element name="AddValuesRequest" type="tns:AddValuesType" />
            <xs:element name="AddValuesResponse" type="tns:AddValuesResponseType" />

            <xs:complexType name="AddValuesType">
                <xs:sequence>
                    <xs:element name="FirstValue" type="xs:int" minOccurs="1" maxOccurs="1" />
                    <xs:element name="SecondValue" type="xs:int" minOccurs="1" maxOccurs="1" />
                </xs:sequence>
            </xs:complexType>

            <xs:complexType name="AddValuesResponseType">
                <xs:sequence minOccurs="1" maxOccurs="1">
                    <xs:element name="Result" type="xs:int" />
                </xs:sequence>
            </xs:complexType>

            <xs:attribute name="Timestamp" type="xs:dateTime" />
            <xs:element name="CalculationFault">
                <xs:complexType>
                    <xs:sequence>
                        <xs:element name="ErrorCode" type="xs:int" />
                        <xs:element name="Reason" type="xs:string" />
                    </xs:sequence>
                    <xs:attribute ref="tns:Timestamp" use="required" />
                </xs:complexType>
            </xs:element>

        </xs:schema>
    </wsdl:types>

    <!--
        Abstract interface
    -->

    <wsdl:interface name="CalculatorInterface">
        <wsdl:fault name="fault" element="calc:CalculationFault" />
        <wsdl:operation name="AddValues" pattern="http://www.w3.org/ns/wsdl/in-out" style="http://www.w3.org/ns/wsdl/style/iri" wsdl:safe="true">
            <wsdl:documentation>Adds up passed values and returns the result</wsdl:documentation>
            <wsdl:input messageLabel="in" element="calc:AddValuesRequest" />
            <wsdl:output messageLabel="out" element="calc:AddValuesResponse" />
            <wsdl:outfault messageLabel="fault" ref="tns:fault" />
        </wsdl:operation>
    </wsdl:interface>

    <!--
        Concrete binding definition
    -->

    <wsdl:binding name="CalculatorBinding" interface="tns:CalculatorInterface" type="http://www.w3.org/ns/wsdl/soap" soap:protocol="http://www.w3.org/2003/05/soap/bindings/HTTP/">
        <wsdl:operation ref="tns:AddValues" soap:mep="http://www.w3.org/2003/05/soap/mep/soap-response" />
        <wsdl:fault ref="tns:fault" soap:code="soap:Sender" />
    </wsdl:binding>

    <!--
        Concrete service definition
    -->

    <wsdl:service name="CalculatorService" interface="tns:CalculatorInterface">
        <wsdl:endpoint name="CalculatorEndpoint" binding="tns:CalculatorBinding" address="http://localhost:8080/services/calculator" />
    </wsdl:service>

</wsdl:description>

WSDL 1.1 和 2.0 之间的差异

有关两个版本之间差异的图形概述,请参见下图。

StackOverflow 文档来源

从图像中可以看出,message 部分被移除了,现在包含在 interface 部分中。此外,一些元素已重命名,其他元素具有不同的语法,但通常两个 WSDL 版本与版本 2.0 基本相同,与 1.1 相比需要更少的写入开销。

除了通过 WSDL 2.0 定义基于 SOAP 的服务的占地面积较小之外,较新的版本还提供了定义 REST 服务的功能, 尽管 WSDL 2.0 甚至 WADL 不建议用于 RESTful 服务,因为它们与其背后的实际想法相矛盾。

喜欢哪种风格

WSDL 绑定部分描述了服务如何绑定到 SOAP 消息传递协议。上面的示例使用 document 作为绑定样式,只要结果输出是有效的 XML 实例,就可以按照我们想要的方式构造 SOAP 主体。这是默认的绑定样式,通常称为 Message-Oriented style

document 样式相比,RPC 样式请求体必须包含操作名称和方法参数集。因此,XML 实例的结构是预定义的,无法更改。

除了绑定样式之外,绑定部分还定义了一个转换模型,用于以 literalencoded 的名义绑定到 SOAP 消息。两者之间的区别在于,literal 模型必须符合用户定义的 XSD 结构,可用于验证请求和响应,而 encoded 模型必须使用像 xs:integerxs:string 这样的 XSD 数据类型,但是因此具有不符合任何用户定义的架构。但是,这使得更难以验证消息体或通过 XSLT 将消息转换为其他格式。

绑定样式与使用模型的组合实际上允许 4 种不同的消息结果。第 5 个条目被添加到常用的列表中(虽然不是标准的一部分)。

  • RPC /编码
  • RPC / literal
  • 文件/编码
  • 文件/文字
  • 文件/文字(包裹)

在文档/文字样式的消息传递中,存在一种称为 wrapped-document / literal 的模式。这只是一种模式,并不是 WSDL 规范的一部分。在 JSR 224(JAX-WS:基于 XML 的 Web 服务的 Java API)中提到了这种模式。 ( 来源

以下部分概述了有关 WSDL 或模式声明的差异及其在更改绑定样式或使用模型定义时对生成的 SOAP 消息格式的影响。

RPC /编码

WSDL:

...
<wsdl:message name="AddValues">
  <wsdl:part name="FirstValue" type="xsd:int" />
  <wsdl:part name="SecondValue" type="xsd:int" />
</wsdl:message>
<wsdl:message name="AddValuesResponse">
  <wsdl:part name="Result" type="xsd:int" />
</wsdl:message>

<wsdl:portType name="CalculatorEndpoint">
  <wsdl:operation="AddValues">
    <wsdl:input message="AddValues" />
    <wsdl:output message="AddValuesResponse" />
  </wsdl:operation>
</wsdl:portType>

<!-- binding style set to 'RPC' and use to 'encoded' -->
...

SOAP 请求

<soap:envelope>
  <soap:body>
    <AddValues>
      <FirstValue xsi:type="xsd:int">1</FirstValue>
      <SecondValue xsi:type="xsd:int">2</SecondValue>
    </AddValues>
  </soap:body>
</soap:envelope>

SOAP 响应

<soap:envelope>
  <soap:body>
    <AddValuesResponse>
      <Result xsi:type="xsd:int">3</Result>
    </AddValuesResponse>
  </soap:body>
</soap:envelope>

优点

  • 直截了当的 WSDL
  • 请求和响应中可用的操作名称和元素

缺点

  • XSI 类型的明确声明
  • 很难验证
  • 不符合 WS-I 标准

RPC / literal

WSDL:

...
<wsdl:message name="AddValues">
  <wsdl:part name="FirstValue" type="xsd:int" />
  <wsdl:part name="SecondValue" type="xsd:int" />
</wsdl:message>
<wsdl:message name="AddValuesResponse">
  <wsdl:part name="Result" type="xsd:int" />
</wsdl:message>

<wsdl:portType name="CalculatorEndpoint">
  <wsdl:operation="AddValues">
    <wsdl:input message="AddValues" />
    <wsdl:output message="AddValuesResponse" />
  </wsdl:operation>
</wsdl:portType>

<!-- binding style set to 'RPC' and use to 'literal' -->
...

SOAP 请求

<soap:envelope>
  <soap:body>
    <AddValues>
      <FirstValue>1</FirstValue>
      <SecondValue>2</SecondValue>
    </AddValues>
  </soap:body>
</soap:envelope>

SOAP 响应

<soap:envelope>
  <soap:body>
    <AddValuesResult>
      <Result>3</Result>
    </AddValuesResult>
  </soap:body>
</soap:envelope>

优点

  • 直截了当的 WSDL
  • 请求和响应中可用的操作名称和元素
  • 不需要 XSI 类型规范
  • 符合 WS-I 标准

缺点

  • 很难验证

文件/编码

因此省略没有任何意义。

文件/文字

WSDL:

...
<types>
  <schema>
    <element name="FirstValueElement" type="xsd:int" />
    <element name="SecondValueElement" type="xsd:int" />
    <element name="ResultValueElement" type="xsd:int" />
  </schema>
</types>

<wsdl:message name="AddValues">
  <wsdl:part name="FirstValue" element="FirstValueElement" />
  <wsdl:part name="SecondValue" element="SecondValueElement" />
</wsdl:message>
<wsdl:message name="AddValuesResponse">
  <wsdl:part name="Result" element="ResultValueElement" />
</wsdl:message>

<wsdl:portType name="CalculatorEndpoint">
  <wsdl:operation="AddValues">
    <wsdl:input message="AddValues" />
    <wsdl:output message="AddValuesResponse" />
  </wsdl:operation>
</wsdl:portType>

<!-- binding style set to 'Document' and use to 'literal' -->
...

SOAP 请求

<soap:envelope>
  <soap:body>
    <FirstValueElement>1</FirstValueElement>
    <SecondValueElement>2</SecondValueElement>
  </soap:body>
</soap:envelope>

SOAP 响应

<soap:envelope>
  <soap:body>
    <ResultElement>3</ResultElement>
  </soap:body>
</soap:envelope>

优点

  • 没有 XSI 类型编码
  • 能够验证身体
  • WS-I 符合限制

缺点

  • 由于额外的 XSD 定义,WSDL 更复杂
  • 操作名称丢失
  • WS-I 只允许 SOAP 体中的一个子节点

文件/文字(包裹)

WSDL:

...
<types>
  <schema>
    <element name="AddValues">
      <complexType>
        <sequence>
          <element name="FirstValue" type="xsd:int" />
          <element name="SecondValue" type="xsd:int" />
        </sequence>
      </complexType>
    </element>
    <element name="AddValuesResponse">
      <complexType>
        <sequence>
          <element name="ResultValue" type="xsd:int" />
        </sequence>
      </complexType>
    </element>
  </schema>
</types>

<wsdl:message name="AddValues">
  <wsdl:part name="in" element="AddValues" />
</wsdl:message>
<wsdl:message name="AddValuesResponse">
  <wsdl:part name="out" element="AddValuesResponse" />
</wsdl:message>

<wsdl:portType name="CalculatorEndpoint">
  <wsdl:operation="AddValues">
    <wsdl:input message="AddValues" />
    <wsdl:output message="AddValuesResponse" />
  </wsdl:operation>
</wsdl:portType>

<!-- binding style set to 'Document' and use to 'literal' -->
...

SOAP 请求

<soap:envelope>
  <soap:body>
    <AddValues>
      <FirstValue>1</FirstValue>
      <SecondValue>2</SecondValue>
    </AddValues>
  </soap:body>
</soap:envelope>

SOAP 响应

<soap:envelope>
  <soap:body>
    <AddValuesResponse>
      <Result>3</Result>
    </AddValuesResponse>
  </soap:body>
</soap:envelope>

优点

  • 没有 XSI 类型编码
  • 能够验证身体
  • 请求和响应中可用的操作名称和元素
  • 符合 WS-I 标准

缺点

  • 由于额外的 XSD 定义,WSDL 更复杂

UDDI

Universal Description, Discovery and Integration (UDDI) 是一个在 2000 年创建的开放式行业计划,它作为基于 XML 的黄页网页服务注册表,帮助查找解决特定任务的服务。为了找到适当的服务,需要首先使用 Web 服务注册表(如 UDDI)注册服务。

UDDI 处理 SOAP 消息交换,并提供对 WSDL 文档的访问,这些文档可用于调用实际的 Web 服务。

UDDI 提供了诸如的查找标准

  • 业务标识符
  • 公司名称
  • 营业地点
  • 业务类别
  • 服务类型名称
  • 发现网址

但是,当前 UDDI 的一大缺点是它只允许在搜索语句中使用一个单一条件。因此,某些实现者将其 UDDI 实现模块化,以允许同时生成多个 UDDI 的查询,然后聚合返回的结果。

然而,在实践中,经常不使用 UDDI。有些人甚至说 UDDI 已经死了,因为 IBM,微软和 SAP 在 2005 年关闭了他们的 UDDI 服务

附加说明:

SOAP / WSDL 提供了广泛的工具支持,并且还允许为客户端和服务器动态生成存根类,因为通过嵌入或链接的 XSD 模式很好地定义了消息和数据交换的类型。

虽然 WSDL 2.0 定义 Web 服务的开销较小,但某些语言尚未采用新标准。即 Java 中流行的工具,如 wsimport(来自 Oracle / Sun)或 wsdl2java(来自 Apache CXF),无法正确处理 WSDL 2.0 描述。因此,出于兼容性原因,仍建议使用 WSDL 1.1。如果你需要在 Java 中开发基于 WSDL 2.0 的 SOAP 服务,请查看来自 Apache Axis2 项目的 wsdl2java

然而,现在比较流行的是基于 HTTP 的 API 服务,它将 HTTP 操作调用与干净的人类可理解的 URI 混合,并对协议进行某些自定义以完成其工作,基于 REST 的服务完全符合实际建议,或者自己的字节级协议,例如 OFTP2

如果你无法将任务直接映射到资源(如 HTTP / REST 基本服务),SOAP 现在仍然很有用,因为要实现的任务自然代表一个操作或必须定义某些事务语义。此外,如果你没有资源来定义或实现自己的协议,那么你最好使用 SOAP。如果你必须处理业务流程,SOAP 特别有用,因为 WSDL 描述与 UDDI 结合允许动态组合服务。