级别: 初级 李 劲 (jinli@ca.ibm.com)IBM软件解决方案多伦多实验室应用开发技术中心
2002 年 10 月 01 日 动态电子商务是电子商务发展的目标,而Web服务是其核心技术,也是Web的下一个革新。Web服务将改变企业之间的商务运作和企业对企业(B2B)的应用的设计与开发。本文摘选自即将出版的
《动态电子商务的web服务》一书第五章,也是调用Web服务系列的第二部分。在
第一部分中,我们讲述了SOAP的架构、基本技术知识、在Web服务应用上常用的技术,本文将讨论如何使用SOAP来调用Web服务。
SOAP绑定
下面将重点描述SOAP的不同传送方法。首先是HTTP绑定,SOAP请求是通过HTTP POST传送出去,由HTTP响应传送回来。使用HTTP绑定时,SOAP规定消息必须使用Content-Type和SOAPAction两个HTTP消息标题,而且Content-Type必须是text/xml。理论上SOAPAction用于代理服务器和防火墙,但是实际上多数SOAP实现不使用SOAPAction。代码表5-11为有关HTTP绑定的示例
代码表5-11 HTTP绑定的示例
<binding name="StockQuoteServiceBinding"
type="tns:StockQuoteService">
<soap:binding style="rpc"
transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="getQuote">
<soap:operation soapAction="" style="rpc"/>
<input name="getQuoteRequest">
<soap:body
encodingStyle="http://schemas.xmlsoap.org/
soap/encoding/"
namespace=http://tempuri.org/StockQuoteService
use="encoded"/>
</input>
<output name="getQuoteResponse">
<soap:body
encodingStyle="http://schemas.xmlsoap.org/
soap/encoding/"
namespace="http://tempuri.org/StockQuoteService"
use="encoded"/>
</output>
</operation>
</binding>
<service name="StockQuoteServiceBinding_service">
<port name="StockQuoteServiceBinding_port"
binding="binding:StockQuoteServiceBinding">
<soap:address location="http://localhost:8080/
StockQuoteWeb/servlet/rpcrouter"/>
</port>
</service>
|
 | |
其次是SMTP绑定,一个异步的传送协议。由于现在SOAP没有正式定义SMTP绑定,所有多数SMTP绑定的实现是基于ebXML的传送规范(请参考http://www.ebxml.org)。代码表5-12为一个SMTP绑定的示例。与HTTP绑定的主要区别是soap:binding元素的style和transport属性值,以及soap:address元素的location属性值。还有,所有的消息都使用literal而不是SOAP encoding格式。这样就可以通过e-mail来发出Web服务请求和收到该服务响应的消息。
代码表5-12 SMTP绑定的示例
<binding name="StockQuoteServiceBinding"
type="tns:StockQuoteService">
<soap:binding style="document"
transport="http://schemas.xmlsoap.org/soap/smtp"/>
<operation name="getQuote">
<input name="getQuoteRequest">
<soap:body use="literal"/>
</input>
<output name="getQuoteResponse">
<soap:body use="literal"/>
</output>
</operation>
</binding>
<service name="StockQuoteServiceBinding_service">
<port name="StockQuoteServiceBinding_port"
binding="binding:StockQuoteServiceBinding">
<soap:address location="mailto:getQuote@test.com"/>
</port>
</service>
|
还有,现在有些公司开始测试FTP绑定的实现,不久的将来会有其他基于SOAP传送绑定框架的传送协议绑定。
带附件的SOAP
接下来,描述一下SOAP 1.1中带附件的传送(SOAP with Attachment)。在实践中,可能经常需要将各种附件(如图像、图画、XML文档等)与SOAP消息一起发送,而这些数据通常是特殊的二进制格式。带附件的SOAP规范地详细说明了使用MIME的multipart/related媒体类型和URI模式引用MIME部件。以下说明如何构造带附件的SOAP消息以及如何从SOAP消息引用附件。SOAP消息包包含XML格式的主SOAP消息以及SOAP信封中未定义但与消息有关的任意数据格式(例如GIF、JPEG和XML等)的其他实体。代码表5-13为一个SOAP消息带一张签了名的索保传真图表claim061400a.tiff附件的示例。
代码表5-13 带附件的SOAP消息的示例
MIME-Version: 1.0
Content-Type: Multipart/Related; boundary=MIME_boundary; type=text/xml;
start="<http://claiming-it.com/claim061400a.xml>"
Content-Description: This is the optional message description.
Content-Location: http://claiming-it.com/
--MIME_boundary
Content-Type: text/xml; charset=UTF-8
Content-Transfer-Encoding: 8bit
Content-ID: <http://claiming-it.com/claim061400a.xml>
Content-Location: claim061400a.xml
<?xml version='1.0' ?>
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
..
<theSignedForm href="claim061400a.tiff"/>
..
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
--MIME_boundary
Content-Type: image/tiff
Content-Transfer-Encoding: binary
Content-Location: claim061400a.tiff
...binary TIFF image...
--MIME_boundary-
|
如代码表5-13所示,SOAP消息包是用MIME的multipart/related媒体类型构建的,每个部件都嵌入MIME边界(在Context-Type报头中定义)。每个MIME部件都有报头信息,比如Context-Type(它指定嵌入这个MIME部件的数据的类型)、Content Transfer-encoding(指定用于这个MIME部件的编码)、Content-ID或者Content-Location(作为从MIME包的任何地方引用这些内容的标识符)。MIME消息的根部件包含SOAP信封,Content-Type被设置为text/xml。SOAP报头和SOAP消息的主体都可以引用消息包中的其他实体。根据SOAP 1.1编码规则,SOAP的href属性可用于引用任何资源。任何资源都可以使用Content-ID或者Content-Location引用。如果使用Content-ID作为标识符,那么模式属性(例如href)必须使用URL模式CID(根据RFC2153)。如果使用Content-Location作为标识符,那么必须根据带附件的SOAP规范中指定的规则进行解析,其中解析是基于下列要素之一:
- 绝对URI引用:在SOAP信封中的Content-Location和href属性中指定的。
- 相对URI引用:MIME消息主报头的Content-Location中指定了一个基础base URL,对所有的相对URL都是使用这个基础URL进行引用。
- 不带基础URI的相对URI:主报头的Content-Location中没指定基础URI,但使用消息的基础URL,并且对所有的相对URL都是使用这个基础URL进行引用。
代码表5-13中的示例为使用相对URI引用。如果HTTP绑定被SOAP用来发送附件,那么就需要修改HTTP报头使其包含来自SOAP MIME包报头的Content-Type信息。HTTP报头中不包含来自MIME包报头的其他报头信息。所有的MIME部件都包含SOAP信封部件和其他附件,构成HTTP主体。对于SMTP绑定来说,所有的多部件MIME报头都会被作为SMTP报头的一部分存储。这样,SOAP处理器和应用程序就应该知道这些报头与不同种类的SOAP绑定的不兼容性。代码表5-14为一个包含两个SOAP附件的汽车保险申报表的HTTP请求消息,一个附件是签了名的索保图表,另一个附件是被损坏了的汽车图片。
代码表5-14 包含两个SOAP附件的HTTP请求消息
POST /insuranceClaims HTTP/1.1
Host: www.risky-stuff.com
Content-Type: Multipart/Related; boundary=MIME_boundary; type=text/xml;
start="<claim061400a.xml@claiming-it.com>"
Content-Length: XXXX
SOAPAction: http://schemas.risky-stuff.com/Auto-Claim
Content-Description: This is the optional message description.
--MIME_boundary
Content-Type: text/xml; charset=UTF-8
Content-Transfer-Encoding: 8bit
Content-ID: <claim061400a.xml@claiming-it.com>
<?xml version='1.0' ?>
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<claim:insurance_claim_auto id="insurance_claim_document_id"
xmlns:claim="http://schemas.risky-stuff.com/Auto-Claim">
<theSignedForm href="cid:claim061400a.tiff@claiming-it.com"/>
<theCrashPhoto href="cid:claim061400a.jpeg@claiming-it.com"/>
<!-- ... more claim details go here... -->
</claim:insurance_claim_auto>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
--MIME_boundary
Content-Type: image/tiff
Content-Transfer-Encoding: base64
Content-ID: <claim061400a.tiff@claiming-it.com>
...Base64 encoded TIFF image...
--MIME_boundary
Content-Type: image/jpeg
Content-Transfer-Encoding: binary
Content-ID: <claim061400a.jpeg@claiming-it.com>
...Raw JPEG image..
--MIME_boundary--
|

 |

|
SOAP绑定描述
如何描述这些不同的绑定呢?WSDL标准规范定义了一个灵活的方法,使WSDL中的绑定元素可以被扩展去描述不同的消息和传送协议。WSDL标准规范明确地描述了3种绑定扩展:SOAP/HTTP、HTTP GET/POST和SOAP with MIME attachments。现共有4种SOAP绑定扩展方式,在这里将逐一介绍它们。
- Invocation style
- SOAPAction
- Input message appearance
- Output message appearance
首先是invocation style,代码表5-15这个示例说明所有的SOAP操作将被定义成SOAP消息,而且style属性表示所有的操作将会使用RPC来调用。style属性的默认值是document,可以在每个operation元素里更换这个属性值。
代码表5-15 SOAP绑定扩展的style属性示例
<soap:binding style="rpc"
transport="http://www.w3.org/soap/http" />
|
其次,代码表5-16这个示例说明在HTTP消息的标题中必须使用什么样的SOAPAction值。前面已经介绍过SOAPAction的目的是通过路径信息给SOAP routers。从这个示例中,可以看到同一个portType里不同的operation可以使用不同的SOAPAction。
代码表5-16 SOAPAction示例
<operation name="m1">
<soap:operation soapaction="http://www.test.com/test/hello">
<operation name="m2">
<soap:operation soapaction="http://www.test.com/test/goodbye">
|
第3种SOAP绑定扩展定义如何描述SOAP消息中的输入消息。代码表5-17这个示例显示整个输入消息是摘要(因为使用use="encoded"),XML数据内容需要使用encodingStyle的编码规则来解码。如果这个SOAP绑定使用RPC调用方式,那么此输入消息将会是RPC的参数之一。
代码表5-17 SOAP绑定扩展的输入消息示例
<input>
<soap:body use="encoded" namespace="http://www.test.com/test"
encodingStyle="http://www.w3.org/soap/soap-encoding" />
</input>
|
最后一种SOAP绑定扩展定义如何描述SOAP消息中的输出消息,它与输入消息的描述相同,所以在这里不再举示例。使用这些SOAP绑定扩展时,可以选择不同的Header、Fault和HeaderFault元素的格式。
由代码表5-18这个示例可看出,soap:header元素定义expiration消息将会是SOAP Header消息的一部分,但是其他的消息将会在SOAP Body消息中。那么,soap:fault扩展定义是如何把Fault元素映射到SOAP规范上呢?代码表5-19为一个soap:fault扩展示例:
代码表5-18 soap:header示例
<operation name="m1">
<soap:operation soapaction="http://www.test.com/test/hello">
<input>
<soap:header message="m1Request"
part="expiration" use="encoded"
namespace="http://www.test.com/test"
encodingStyle="http://www.w3.org/soap/soap-encoding" />
</input>
|
代码表5-19 soap:fault示例
<operation name="m1">
<fault name="m1ErrorMessage">
<soap:fault name="m1ErrorMessage"
namespace="http://www.test.com/test"
encodingStyle="http://www.w3.org/soap/soap-encoding" />
</fault>
|
SOAP规范要求处理Header时所有的错误必须以标题形式而不是Fault消息内容形式传送,例如MustUnderstand错误。WSDL规范为此而定义了soap:headerfault元素。如代码表5-20所示。
代码表5-20 soap:headerfault示例
<operation name="m1">
<soap:operation soapaction="http://www.test.com/test/hello">
<input>
<soap:header message="m1Request"
part="expiration" use="encoded"
namespace="http://www.test.com/test"
encodingStyle="http://www.w3.org/soap/soap-encoding"/>
<soap:headerfault message="m1ExpirationError"
part="errorString" use="encoded"
namespace="http://www.test.com/test"
encodingStyle="http://www.w3.org/soap/
soap-encoding" />
</input>
|
追踪SOAP消息
在开发基于SOAP的Web服务时,如何确定收发的SOAP消息是正确的呢?Apache SOAP有一个名为TCP Tunnel的辅助工具,专门提供追踪SOAP消息的功能,使用户可以清楚地了解收发的SOAP请求和响应消息的具体内容。
如图5-4所示,TCP Tunnel是代理监听一个端口,然后把信息转送到另一个端口,同时显示转送的信息。如果使用Apache SOAP的TCP Tunnel工具,启动tcptunnel.bat文档就可以了,而运行时端口5403将被监听。
图5-4 通过TCP Tunnel追踪SOAP消息
下面介绍如何使用IBM的WSAD开发工具来追踪SOAP消息。WSAD拥有一个TCP/IP监听服务器工具,方便追踪SOAP消息的具体内容。使用服务器透视图,通过菜单项中的"
文件→新建→服务器及配置"来启动WSAD的服务器生成向导,如图5-5所示。创建了TCP/IP监听服务器后,它将会被显示在服务器配置视图中。如果使用它,必须首先启动Web应用服务器,然后启动此TCP/IP监听服务器。如果启动成功,控制台会显示以下信息:
Monitoring server started
localhost:8081 -> localhost:8080
这表示TCP Tunnel正在监听8081端口,然后把信息转送到提供Web服务的8080端口,同时显示转送的信息。用户可以通过服务器配置编辑器改变这些端口。
图5-5 WSAD的服务器生成向导
现在通过第3章中的电话号码簿员工查询Web服务示例来说明如何监听SOAP消息。单击示例的TestClient.jsp文档,选择菜单项中的"Run on server"来启动此Web服务。通过菜单项中的"
视窗→视图→TCP/IP监听"来显示TCP/IP监听视图。如果想追踪SOAP消息的具体内容,必须改变此Web服务的端点,从8080变成8081。这可以通过TestClient.jsp的setEndpoint方法,也可以通过修改生成的Java代理程序方法来完成。将此Web服务的端点改成8081后,可以清楚地看到SOAP消息的具体内容,如图5-6所示。
图5-6 TCP/IP监听视图
总 结
到目前为止,我们已经讲述了SOAP的架构、基本技术知识、在Web服务应用上常用的技术以及如何使用SOAP来调用Web服务, 接下来,我们将讨论Web服务请求者开发时场景和不同的Web服务访问方法。然后,介绍Web服务代理程序的编制、生成和作用。
参考资料
- 调用Web服务系列
第一部分讲述了SOAP的架构、基本技术知识、在Web服务应用上常用的技术。
- 《动态电子商务的Web服务》一书第一章:
动态电子商务的Web服务:电子商务的演变
-
《动态电子商务的Web服务》一书即将由清华大学出版社于2002年11月出版。该书描述了有关动态电子商务的Web服务的概念和理论,并且显示了相应的程序源码和样本应用,演示了如何使用IBM的WSAD开发工具来创建Web服务和基于Web服务的J2EE应用。以多个有代表性的、基于Web服务应用的具体案例,来详细说明使用Java的实施过程以及在实施过程中应注意的事项。通过基础理论、场景示例和应用程序示例来介绍和解释Web服务的技术,包括:WSDL、SOAP、UDDI、WSFL、WSIF等。本书针对广大的中国软件开发者而写,内容深入浅出,理论结合实际,有较强的实用性。在
《动态电子商务的Web服务》网页上包括内容简介、完整的目录以及定购该书的方法。
-
将应用程序的功能封装成为Web Services一文介绍了如何用IBM的开发工具WebSphere Studio Application Developer(WSAD)来定义、发布、定位和调用Web服务。
- 在developerWorks的
Web services专区查找更多的资料。
关于作者  | |  | 李劲, IBM软件解决方案多伦多实验室应用开发技术中心的部门负责人,他负责从收集用户要求到软件实现及测试的全部设计周期,即收集、分析用户的要求,并在软件以及WebSphere应用开发工具和面向Web应用的交互式设计技术,实现用户的要求和使用方案。 Jin目前的主要工作是Web服务和B2B应用集成,他具有十多年的软件业从业经验,曾多次使用VisualAge实现了IBM的Java和WebSphere应用服务器的客户承诺. 可以通过
jinli@ca.ibm.com与他联系.
|
对本文的评价
|