柴晓路 Chief System Architect 2001 年 10 月
本文应SOAP/1.2规范推出的技术背景,就运用SOAP Header扩展SOAP的功能展开讨论。当具体的应用中运用了一些与应用本身关联不是太大而更面向底层控制的服务的时候应当采用SOAP Header来传输这些控制信息,理由是这些服务往往是平台的功能而非具体应用所要实现的功能。从体系架构的观点来看,解析SOAP Header的就可以由平台模块来完成,通过插入不同的标准化的SOAP Header条目解析模块来完成不同目的的控制功能。而相应的,解析SOAP Body是由应用模块来完成。这样在开发和部署上将会非常地清晰。
W3C XML Protocol工作组在今年7月发布了SOAP Version 1.2 Working Draft (SOAP规范1.2版草案,网址是" http://www.w3.org/TR/2001/WD-soap12-20010709/")。同时在2001年4月,在美国的San Jose召开的Web服务研讨会上正式确立了SOAP作为Web服务的核心规范的地位。
在SOAP/1.2版中,对于如何拓展SOAP的能力作了明确的指示性的描述,那就是SOAP Body关注于调用本身(基本没有变化),而SOAP Header从先前的可以由SOAP中介结点处理的模糊指示转变为SOAP Header是扩展SOAP功能的最佳途径的明确性指示。
我们知道,SOAP的应用已经有了一定的阶段,各种基于SOAP调用的Web服务纷纷出现。然而,目前的应用模式基本上停留在远程过程/对象的调用上,基于多次协调调用或者遵循上下文的调用模式尚很少使用,这其实是受简单的SOAP消息的制约。如果扩展,而且是遵循标准的扩展SOAP消息以满足更复杂情况下的应用成为了目前的一个发展趋势。
更新的SOAP概念
在讨论运用SOAP Header来扩展SOAP功能之前,我们先来看看SOAP/1.2中更新的一些SOAP的基本概念,这些是理解后面的内容的基础。
SOAP结点 (SOAP Node)
SOAP结点根据SOAP定义的整套规范来处理SOAP消息。SOAP结点有责任遵守SOAP消息交换的规则以及提供通过依赖底层协议的SOAP绑定来访问的服务。任何不符合SOAP约定的情况都将导致SOAP结点产生一个SOAP fault(SOAP错误)。
SOAP条目 (SOAP Block)
SOAP条目是一个句法上的结构,它用于包含一个逻辑上的单一元素,这一元素是需要被SOAP结点处理的。一个SOAP条目是由该条目最外层元素的完整修饰名(带命名空间修饰)所标识的,这个完整修饰名是由一个局部名和一个命名空间URI组成的。封装在SOAP Header中的SOAP条目称为Header条目,而封装在SOAP body中的SOAP条目为Body条目。
SOAP Header (SOAP头)
能够被SOAP消息传输路径中任意的SOAP接受者结点处理的一组SOAP条目(0个或多个)。
SOAP Body (SOAP体)
能够被SOAP消息路径中的最终SOAP接受结点处理的一组SOAP条目(0个或多个)。
SOAP发送者
SOAP发送者是发出SOAP消息的SOAP结点。
SOAP接收者
SOAP接收者是接受SOAP消息的SOAP结点。
SOAP消息路径
为传送一个简单的SOAP消息而要经过的一组SOAP发送者和SOAP接受者。其中包含了初始SOAP发送者、零个或多个SOAP中介结点以及最终的SOAP接受者。
初始SOAP发送者
SOAP消息的最初产生者,同时也是SOAP消息路径的第一个结点。
SOAP中介结点
SOAP中介结点即是SOAP接收者也是SOAP发送者,是SOAP消息可到达的某一个应用程序。当SOAP消息沿着SOAP消息路径传输时,SOAP中介结点将处理一组确定的SOAP条目,然后它将消息转发给消息路径的下一个SOAP结点,直至传送到最终SOAP接收者。
最终SOAP接收者
由初始SOAP发送者指定的通过SOAP消息路径传送的SOAP消息的最终的接收者。如果在SOAP消息路径中有SOAP结点产生了SOAP错误,那么SOAP消息将不会到达最终接收者。
同时SOAP/1.2使用了新的命名空间,命名空间前缀"env"和"enc"等关联的SOAP/1.2命名空间分别位于:"http://www.w3.org/2001/06/soap-envelope"和"http://www.w3.org/2001/06/soap-encoding"。
SOAP角色与SOAP Header处理模式
当SOAP结点接受并处理一个SOAP消息的时候,该SOAP结点将被告知应当以一个或多个SOAP处理角色来处理,这些SOAP角色是由SOAP角色名来标识,SOAP角色名的具体表示是使用一个env:actor属性来表示,其值是一个URI。
每个SOAP结点都必须以一个指定的角色来处理,也就是说任意一个SOAP结点都属于这个角色,这个角色使用命名为"http://www.w3.org/2001/06/soap-envelope/actor/next"的SOAP角色来表示,同时可以按照需要应用零个或多个其他的SOAP额外角色,当然这些角色应当使用不同与前面介绍的这个SOAP角色名。
SOAP结点可以通过以匿名SOAP角色来实施处理以使得自己成为最终SOAP接收者。当SOAP结点在处理一个SOAP消息的时候,其表现出的SOAP角色在整个处理过程中不得更改。这是因为SOAP规范只涉及如何处理单个SOAP消息而无需考虑状态(这也是SOAP设计目标之一的简明性的体现),因此是否允许在处理单个SOAP消息的时候转换角色是没有意义的。
从本质上说,SOAP角色名是用来识别SOAP结点的,通常使用某种URI的形式,SOAP的角色名并没有与路由或者消息交换的语义相联系。举例来说,一个SOAP角色可以被命名为一个用于在发送SOAP消息给适当SOAP结点中表示接收结点访问入口的URI。相反,也有这样一些SOAP角色的名字,这些名字或者直接和消息路由相联系(例如,"http://example.org/banking/anyAccountMgr"),或者和路由没有联系(例如,当一个消息头被用来携带这样一种指示性的信息,该指示信息用于告知任何相关的SOAP消息的接受应用软件,这个SOAP消息是长期不变的,因此是能够被安全的缓存和重用的,在这种SOAP消息头中,可以利用一个标识"所有缓存管理软件"的URI来指明SOAP角色),通过名字使用这些SOAP角色也是合适的。
总而言之,SOAP角色的名并没有预定义为一定要与某种语义相关联,用户可以使用某种语义关联的URI来表示,也完全可以用类似UUID这样的没有语义的URI来表示,这完全要看具体的应用的需要。
SOAP Header条目包含可选的env:actor属性,用来把他们定位到合适的SOAP结点。没有该属性的SOAP Header隐含地被定位到一个匿名的SOAP角色,这意味着他们将被最终SOAP接收者所处理。我们把SOAP actor属性的值(隐含的或者直接指明的)作为相应SOAP条目(SOAP Header条目或者SOAP Body条目)的SOAP角色。
如果是:
- SOAP条目中SOAP actor属性的值(如果出现的话)匹配了一个SOAP结点的角色;
- 或者是当SOAP条目没有actor属性(不仅对于SOAP Header条目有效,也同时包括SOAP Body条目,值得注意的是在SOAP/1.1中,actor属性只能应用于SOAP Header条目),而该SOAP结点已经被假设为匿名SOAP角色。
这时我们就说SOAP条目被指向一个SOAP结点,同时将被该SOAP结点处理。
Figure 1. SOAP Header条目的标准化处理模式
我们认为随着时间的过去,会有大量的SOAP Header函数规范出现,而且每个SOAP结点都可以包含一个或多个处理这些扩展所必须的软件。如果SOAP结点的应用软件是完全兼容而且实现了那些由条目中完整修饰的最外层元素名所传递的语义,我们说这个SOAP Header被一个SOAP结点理解。
在Figure 1中,以形象化的形式描述了这种将来可能的依据某种Header函数规范的标准化处理方式。其实质就是在SOAP的框架下,定义了一整套SOAP Header条目的语义集及其处理规范。例如,将来可能会出现一组专用于访问控制的SOAP Header条目集。其中可能包含这样两种SOAP Header条目:(假定他们的命名空间为xmlns:auth="soap:header: authentication")
- 用户认证:auth:get_authToken,在这个SOAP Header条目下,包含两个子元素userID和password,用于完成用户认证操作并获取认证令牌;
- 访问授权:auth:judge_accessList,在这个SOAP Header条目下,包含一系列的子元素accessResource,每个accessResource有两个属性authToken和resourceURI,分别用于表示提供的认证令牌和待访问的资源URI,这个SOAP Header条目用于判定这些资源是否授权于给定的人证令牌以访问权限,如果是,那么授予了什么样的权限。
如果这样一种SOAP Header条目的规范被投入实用后,任何SOAP结点只需要部署了兼容该规范的SOAP处理程序,就能够处理这样的SOAP Header条目。
对于SOAP结点而言,除env:actor属性之外,尚有另一个重要的属性:env:mustUnderstand。当定位到一个SOAP结点的SOAP Header条目的env:mustUnderstand属性为"1",被指向的SOAP结点必须:
- 或者依照由条目中完整修饰的最外层元素名传递的语义来处理SOAP块;
- 或者更本不处理SOAP消息而失败。
也就是说,不可以在任何情况下忽略对这种SOAP Header条目的处理。
SOAP功能扩展: 权限认证
在以下的篇幅,将结合具体的应用实例来详细地阐述SOAP Header条目的意义以及SOAP Header属性的作用,同时期望大家能够了解到从设计者的角度,是如何对SOAP进行体系架构的。
第一个例子是利用SOAP Header条目进行权限认证:
<env:Header xmlns:env="http://www.w3.org/2001/06/soap-envelope" >
<auth:authentication xmlns:auth="http://example.org/authentication "
env:actor="authentication:signin_service"
env:mustUnderstand="1">
<auth:userID>testuserid</auth:userID>
<auth:password>[encodedPassword]</auth:password>
<auth:redirection>http://example.com/service/</auth:redirection>
</auth:authentication>
</env:Header>
|
在这个例子中,SOAP Header条目authentication被交付给专门的权限认证Web服务进行用户认证(该服务使用角色名"authentication:signin_service"来标识),该Web服务通过检查authentication条目中包含的用户名(userID)和密码(password)来确认该用户是否能通过认证检查。如果无法通过认证检查,将返回调用者一个SOAP错误,如果能够通过认证检查,则该认证Web服务在该Header条目中删除userID和password,然后插入一个新的元素authInfo,这是一个认证令牌,可用于以后在需授权服务调用中使用。接着,该Web服务将这条消息传递给由redirection元素指定的地址的Web服务,这个Web服务可以通过校验认证令牌以审核该次调用。
从认证Web服务发送到后续Web服务的SOAP消息中的Header片断的可能内容可参见下面的代码段:
<env:Header xmlns:env="http://www.w3.org/2001/06/soap-envelope" >
<auth:authentication xmlns:auth="http://example.org/authentication "
env:mustUnderstand="1" >
<auth:authInfo>[encodedAuthInfo]</auth:authInfo>
</auth:authentication>
</env:Header>
|
大家可以发现在这个后续的SOAP消息中,authentication条目中的redirection元素也已经被删除了(也就是已经被使用了,作为新的SOAP结点的地址)。
SOAP功能扩展: 事务控制
第二个例子是利用SOAP Header条目进行事务控制。这个应用背景是这样的,在一个商务事务处理应用环境中,由Web服务A发起事务,一个事务会包含多个操作,而这些操作可能要经过其他的一些Web服务进行计算后才能生成,而所有的操作将会被发往Web服务Z,由Web服务Z完成整个事务。整个事务的执行模式可参见下图。
Figure 2. 事务控制模型
其中的消息序列将是这样:
- Web服务A向Web服务Z发出事务启动的总控消息;
- Web服务A向Web服务G、H、I发出操作生成请求消息;
- Web服务G、H、I分别向Web服务Z发出事务中的具体操作的描述消息,以最终完成整个事务。
也就是说Web服务A是事务的控制点,Web服务Z是事务的提交点,而Web服务G、H、I则分别是事务的产生点。
总控消息的Header片断的内容为:
<env:Header xmlns:env="http://www.w3.org/2001/06/soap-envelope" >
<transaction:transaction
xmlns:transaction="http://example.org/transaction"
env:actor="transaction:submission_point">
env:mustUnderstand="1">
<transaction:transactionKey>8259bd00-2f9c-4493-a09f-414e3a4559a6
</transaction:transactionKey>
<transaction:operations>
<transaction:count>3</transaction:count>
</transaction:operations >
</transaction:Transaction>
</env:Header>
|
在这条消息中,有一个SOAP Header条目transaction,它的子元素transactionKey表示了启动的事务的键值。而另一个子元素operations则包含了一个描述该事务包含的所有操作的数量的子元素count。当Web服务Z接受到这条消息后,将为该事务启动一个消息池,该消息池的标识为transactionKey的值。
然后Web服务A向Web服务G、H、I发出事务启动消息,通知这些服务指定事务可以开始提交操作了。
<env:Header xmlns:env="http://www.w3.org/2001/06/soap-envelope" >
<transaction:transaction
xmlns:transaction="http://example.org/transaction"
env:actor="transaction:operation_point" >
env:mustUnderstand="1">
<transaction:transactionKey>8259bd00-2f9c-4493-a09f-414e3a4559a6
</transaction:transactionKey>
<transaction:action>start</transaction:action>
</transaction:Transaction>
</env:Header>
|
当Web服务G、H、I分别向Web服务Z发出操作消息(参见图 4 25)时,Web服务Z分别将这些收到的消息放入指定的消息池中,当消息池中的操作消息的数量达到count元素中指定的数量后,Web服务Z将关闭该消息池,按照次序,执行该事务,待执行完毕后,向Web服务A发送一个通知消息。
<env:Header xmlns:env="http://www.w3.org/2001/06/soap-envelope" >
<transaction:transaction
xmlns:transaction="http://example.org/transaction"
env:actor="transaction:submission_point" >
env:mustUnderstand="1">
<transaction:transactionKey>8259bd00-2f9c-4493-a09f-414e3a4559a6
</transaction:transactionKey>
<transaction:operations>
<transaction:serialNo>1</transaction:serialNo>
</transaction:operations >
</transaction:Transaction>
</env:Header>
|
小结
在本文中按照SOAP规范的约定,给出了两个运用SOAP Header条目对SOAP的能力进行扩充的例子。我们认为,当具体的应用中运用了一些与应用本身关联不是太大而更面向底层控制的服务的时候应当采用SOAP Header来传输这些控制信息,理由是这些服务往往是平台的功能而非具体应用所要实现的功能。按照规范的约定,SOAP Body是专用于交换调用的具体信息,而控制信息的交互应当由SOAP Header来完成。
这样,从体系架构的观点来看,解析SOAP Header的就可以由平台模块来完成,通过插入不同的标准化的SOAP Header条目解析模块来完成不同目的的控制功能。而相应的,解析SOAP Body是由应用模块来完成。这样在开发和部署上将会非常地清晰。
随着SOAP Header扩展的普遍应用和标准的形成,将意味着SOAP技术的真正成熟。 |