初探 SOAP&Web Service

因为明天要去见 Bill.Gates (详见 《2001 微软开发者成功之路大会》),所以今天花了一天时间了解一下今年以来 Microsoft 大肆鼓吹的 SOAP 技术,也好明天多听一点东东。虽然我在用 Delphi 6 试做了 SOAP (见 《DELPHI 6 抢先研究 -- BizSnap/SOAP/WebService 之一 -- 一个 Hello world! 的例子》) 后不久就对 SOAP 有了大致的了解,但总觉得不够,所以还是查查资料充充电吧。

首先去的便是 W3C(http://www.w3c.org), 结果只找到两个标准规范: SOAP Vervsion 1.1 SOAP Version 1.2 (草案) 。 SOAP 1.1 是在2000年5月8日由 Microsoft 和 IBM 等公司参与制定的规范,而 SOAP 1.2 则是在今年7月9日由 Microsoft 和 Sun 等公司制定的一个草案。这里是这两个文本的中文版: SOAP 1.1 规范中文版 SOAP 1.2 草案中文版

光这些是无论如何不够的,我又上 google 这个搜索引擎去搜了一把,结果却很不幸,差不多一半的内容都跟化工、 肥皂有关,剩下的一半中有价值的也是少得很,把搜索结果翻了几页也没见到多少好东东,不过总算是聊胜于无吧,就把那几篇文字研究了一番。 研究的结果仍然令人失望,除了那两篇规范以外其它的东东大多是对 SOAP 的一些说明性的文字,一些更甚至于就是赤裸裸的广告, 只有一两篇介绍用 VS.net(而且居然还不是用 VC# 而是用的 VB.net ,失败!)做 SOAP 的文章,还有一篇是讲用 Java 做的 Web Service 的。 没辙,只好仔细读了一下 SOAP 的规范,总算是有了一点眉目,不过我对 XML 实在太不熟了,晚上回家赶紧从书厨里找了本 XML 的书恶补了一把, 才算是明白了一个大概。

其实在我用 Delphi 6 试做 Web Services 后看了一些与此有关的文章(包括 SOAP/XML/UDDI 等), 特别是看了李维的文章《樂趣無窮,可能無限的新技術-Web Service》之后, 对 Web Services/SOAP/UDDI 都有了一定的了解。

首先要明确的是:SOAP 即 Simple Object Access Protocol -- 简单对象访问协议。 它只是一种对象间的访问协议!并不是一种新的对象技术,可以说,在这点上, 它跟 DCOM 用的 ORPC(Object Remote Procedure Call,对象远程过程调用)、 CORBA 用的 GIOP(General Inter-ORB Protocol, 通用 ORB 间协议)和 Java 用的 RMI(Remote Method Invocation,远程方法调用)没什么不同。但是除此之外, SOAP 与这些对象间的访问协议有很大的不同,它不与任何一种对象模式相关,它是一种独立的、通用的对象间访问协议, 它是基于 XML 标准的、文本的协议(ORPC/GIOP/RMI都是二进制协议),而 ORPC/GIOP/RMI 都与相应的组件技术密切相关 (不过由于目前很多的 RMI 产品是通过 IIOP -- 通过 TCP/IP 进行数据传输的 GIOP 实现 -- 来实现的, 所以它们可以实现与 CORBA 的互通,但这不影响它们是非开放二进制协议的本质)。 SOAP 的简单原理如下图:

SOAP illustration 1

如上图所示, SOAP 的工作原理就是把对象间的访问请求和响应都打包成 XML 文档,在对象间传递。 而要实现对象无关的访问,各种对象就必须对这个 XML 有规范性的要求,这样不同的对象才相互理解别的对象的请求或响应, 这个规范便是 SOAP 。 SOAP 与 GIOP 类似,是一个抽像的上层的通讯协议,它的实现可以基于其它的通讯协议,因为 SOAP 传递的是 XML 文档, 所以最自然的便是用 HTTP 来实现,正如实际上在 CORBA 中通常都是用 GIOP 在 TCP/IP 上的实现 -- IIOP 来进行对象通讯的。 因为 SOAP 通常是用 HTTP 作为下层通讯手段,所以 SOAP 服务也叫 Web services(今天/18日听微软的说法是:XML web services)。 其分层通讯的原理如下图:

Web service illustration 2

正是因为 SOAP 提供了一种与具体实现无关的对象访问能力,所以它可以将现有的、用不同的技术实现的系统互联起来, 提供相互的数据交流和访问操作。但这种系统间的耦合又是一种很松散的耦合,它并不要对原有系统进行修改,不会影响原有系统的功能, 它只需要在原有系统的基础上加上一个 SOAP 接口即可,这可以算是对原有系统的一个扩展。借助于 SOAP ,各种不同的系统可以互相协作, 形成一个更为强大的大系统。也许正是因为 SOAP 具有这种将各种不同的系统整合在一起的能力, 所以它已经成为当前世界各主要 IT 厂商所竞相支持的技术,包括 IBM, Oracle, Sun, Microsoft, Borland 等。

由于不同的实际对象要通过 SOAP 实现相互访问,就必须将它们的访问请求用 XML 打包,而在收到请求后解包, 它们的响应也相应的要有打包和解包的过程。简单表述如下图:

SOAP request and response

图中客户端对象向服务端发出的二进制请求(Request)被用 XML 编码再包上一个信封(Envelop)后用 Web 客户端 (一般是通过一些 HTTP 控件或用浏览器),通过 HTTP 协议发送到服务端。服务端是一个 Web 服务器,它收到这个 XML 请求后, 拆开信封取出经 XML 编码的客户端请求,用 XML Parser 解析出附合服务端要求的请求内容。注意:虽然这里解析出的请求一般也是二进制的, 但如果服务端用的对象技术与客户端不同时,这个请求就与客户端发出的原始请求不一样,不过它们都表示一样的意思,只是表示方式不同, 在两端按各自要求的方式表达。

图中的服务端对象和客户端对象可以是任何一种对象技术,甚至不一定是对象都可以, 只要它们之间的请求能够通过 XML 以各自都能识别的方式表达即可。如服务端可能是用 EJB 实现的一个中间层, 而客户端却可能是一个嵌在网页中的 ActiveForm ,这在 SOAP 诞生之前是不可思议的事。那时如果服务端是用 EJB , 那只能在网页中嵌入 Java Applet 才行,而如果要用 ActiveForm 的话,服务端就只能用 COM 技术实现,但现在有了 SOAP , 一切的障碍都不复存在了。


第二个与 SOAP 有关的重要概念是 WSDL ,即 Web Service Description Language -- Web 服务描述语言。它是用 XML 来对对象进行描述的一种语言,其实也是 XML ,只是有一定的规范要求。它最常用的是描述对象的接口, 这一点跟 IDL 十分相似,但是它比 IDL 更通用、更开放而且具有更好的扩展性。在早期使用 SOAP Toolkit 等进行 SOAP 应用开发时, 必须手工编写一个 WSDL 文件(类似于 IDL 文件)来描述 SOAP 服务端对象,但现在的 Delphi 6 和 Visual Studio.net 都已经可以根据写好的服务端对象自动导出 WSDL 文件。

服务端提供 WSDL 文件最重要的用途就是向客户端提供服务端接口的描述。而客户端可以在没有任何服务端的开发资料的情况下, 通过导入 WSDL 文件,产生服务端的接口单元。这一操作在 Delphi 6 中被称为"Web services importer",在 Visual Studio.net 中被称为“添加 Web 引用”。 导入服务端的接口文件后,客户端就可以像操作本地对象一样操作服务端对象,并且无须了解服务端对象的实现细节。如下图:

WSDL

下面是一个 WSDL 文件的例子,是从 《DELPHI 6 抢先研究 -- BizSnap/SOAP/WebService 之一 -- 一个 Hello world! 的例子》 一文的例子程序中导出的。

<?xml version="1.0"?>
<definitions xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:xs="http://www.w3.org/2001/XMLSchema"
name="ISoapHelloservice" targetNamespace="http://www.borland.com/soapServices/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">
<message name="GetHelloRequest">
<part name="aID" type="xs:int"/>
</message>
<message name="GetHelloResponse">
<part name="return" type="xs:string"/>
</message>
<portType name="ISoapHello">
<operation name="GetHello">
<input message="GetHelloRequest"/>
<output message="GetHelloResponse"/>
</operation>
</portType>
<binding name="ISoapHellobinding" type="ISoapHello">
<soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="GetHello">
<soap:operation soapAction="urn:MainWM-ISoapHello#GetHello"/>
<input>
<soap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="urn:MainWM-ISoapHello"/>
</input>
<output>
<soap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="urn:MainWM-ISoapHello"/>
</output>
</operation>
</binding>
<service name="ISoapHelloservice">
<port name="ISoapHelloPort" binding="ISoapHellobinding">
<soap:address location="http://localhost/delphi6/soap/soaptest.dll/soap/ISoapHello"/>
</port>
</service>
</definitions>

最后一个与 SOAP 有关的重要概念是 UDDI ,即 Universal Description, Discovery, Integration -- 通用描述、发现与集成。它的功能类似于搜索引擎,用于在 Internet 中注册 Web Services 或者查找合适的 Web Services 。 顾名思义,它是一种通用的技术,Web Services 提供者以一种统一的方式将各种 Web Services 注册到 UDDI 注册中心, 用户就可以通过 UDDI 注册中心方便地找到他们所需的 Web Services 。其工作原理如下图:

UDDI

SOAP/WSDL/UDDI 对 B2B 电子商务应用来说是再合适不过了。举例来说:一个商店可以很容易地通过 UDDI 找到最合适的供货商, 并且通过导入供货商的 Web Services 的 WSDL 文件来建立与供货商的接口,再用 SOAP 将二者的管理系统联系在一起,实现系统整合, 而不用关心二者所用的系统是否相同,他们可以用不同的组件技术,不同的操作系统,甚至是完全不同的硬件。


如上所述, SOAP 是一项非常通用的组件访问技术,也将会是一项非常有前途的技术。当然, 限于水平,以上内容只是个人对 SOAP 的理解,也许有一些不对之处,还望指正。