第四章
1、SOAP消息结构
SOAP消息有一个SOAP Envelope、可选的SOAP Header和一个SOAP Body组成的XML文档。
(1)、SOAP Envelope
SOPA Envelope是SOAP消息的顶级元素。
SOPA Envelope的语法规则如下:
* 元素名为Envelope, 该元素必须在SOAP消息中出现,一般是根元素;
* 该元素可以包含命名空间声明和额外的属性。如果出现额外属性,则必须使用命名空间修饰;
* 该元素可以有额外的子元素,必须有命名空间修饰并且必须跟在SOAP Body元素之后,也就是说,Envelope的直接子元素Header和Body必须排列在最前面。
(2)、SOAP Header
SOPA Header的语法规则如下:
* 元素名为Header。该元素可以在SOAP消息中出现,但并不是必须出现。如果出现,该元素必须是SOAP Envelope元素的第一个直接子元素;
* 该元素可以包含一系列的Header条目,这些条目都应当是Header元素的直接子元素。Header的所有直接子元素都必须有命名空间修饰;
* Header条目自身可以包含下级子元素,但这些元素不是Header条目,而是Header条目的内容,
* 对于那些以非Header条目出现的SOAP Header属性,SOAP消息的接受者必须忽略。
(3)、SOPA Body
SOPA Body的语法规则如下:
* 元素名为Body, 该元素必须在SOAP消息中出现,若消息中有Header元素,Body元素必须相邻排列在Header元素之后,若消息中没有Header元素,Body元素必须是SOAP Envelope的第一个直接子元素;
* 该元素可以包含一系列的Body条目,这些条目都应该是Body元素的直接子元素。Body的所有直接子元素必须有命名空间修饰。 SOAP Fault元素如果存在,必须作为Body的条目,它用来指示调用错误的信息。
* Body元素本身可以包含下级子元素,但这些元素不是Body条目,而是Body条目的内容。
(4)、SOAP Fault
SOAP Fault元素用于在SOAP消息中传输错误和状态信息。如果SOAP消息中存在SOAP Fault元素,它必须作为一个Body条目出现,而且在Body元素内至多出现一次。
SOAP Fault元素有以下子元素:
* faultcode: 必须在SOAP Fault元素中出现
* faultstring : 该元素是为哪些错误代码提供用户可以读懂的错误解释,它并不是为程序处理而设置的。
* faultactor : 该元素描述在消息路径中错误的引发者。它类似于SOAP actor属性,不过它不是指示Header条目的接收者,而是指示错误源。
* detail : 该元素用于传输与Body元素相关的应用程序的错误信息。detail元素的所有直接子元素都称为detail条目,同时每一个detail条目都作为detail元素中的一个独立元素。
2、SOAP 消息交换模型
(1)、SOAP 节点的含义
SOAP节点表示SOAP消息路径的逻辑实体,用于进行消息路由或处理。SOAP节点可以是SOAP消息的发送者、接收方、消息中介。
在SOAP消息模型中,中间方为一种SOAP节点,负责提供发送消息的应用程序和接收方间的消息交换和协议路由功能。中间方节点驻留在发送节点和接收节点之间,负责处理SOAP消息头中定义的部分消息。SOAP发送方和接收方之间可以有0个或多个SOAP中间方,它为SOAP接收方提供分布式处理机制。
一般,SOAP消息中间方分为两种:
* 转发中间方:这一类型的中间方通过在所转发消息的SOAP消息头块中描述和构造语义和规则,从而实现消息处理。
* 活动中间方:这一类型的中间方利用一组功能为接收方节点修改外部绑定消息,从而提供更多的消息处理操作。
在SOAP消息交换路径中,借助于SOAP中间方,使得分布式处理模型在SOAP消息交换中得以实现。通过使用SOAP中间方,可以向SOAP应用程序中集成各种功能(如转发、过滤、事务、安全、日志记录、智能路由等)。
(2)、SOAP节点的作用
接收到SOAP消息的SOAP节点必须能够实时处理并产生必要的SOAP错误和SOAP响应,如果合适的话,还应当根据SOAP规范的后续描述生成额外的SOAP消息。
SOAP header条目包含可选的env:actor属性,该属性用来把条目定位到合适的SOAP节点,没有该属性的SOAP Header隐式地定位到一个匿名的SOAP actor。这意味着该匿名的角色为最终的SOAP接收者。
SOAP actor名字是用来识别SOAP节点的,并没有与路由或消息交换的语义相联系。一个SOAP actor可以被命名为一个用来发送SOAP消息给适当SOAP节点的URI。
注意:当定位到一个SOAP节点的SOAP Header块的mustUnderstand属性为“1”,那么所指向的SOAP节点必须:
* 依照由条目中完整修饰的最外层元素名传递的语义来处理SOAP块;
* 根本不处理SOAP消息而失败。
3、SOAP消息的处理过程
4、SOAP消息的应用模式
(1)、请求/响应模式
当业务应用被调用后,一个包含业务文档的请求将从SOAP发送者发给SOAP接收者,而位于SOAP接收者端的业务应用将处理这个请求并生成响应,这个响应被回送给发出该请求的SOAP发送者。
(2)、“fire-and_forget”模式
该模式下,发出SOAP消息,然后就不再去处理与该消息相关的操作,该模式分为两种情况:一种是面向单个接收者,另一种是面向多个接收者。
** 面向单个接收者的“fire-and-forget”模式
该模式是指:发送者期望向单个接收者发送不被答复的消息。SOAP发送者并不需要了解任何消息状态信息,包括消息是否已经被发送,或者消息是否已经被接收者接收到等。底层传输协议也许实现了一个响应机制,但描述消息是否已成功发送的状态信息不回返回给发送SOAP消息的SOAP处理器。
** 面向多个接收者的“fire-and-forget”模式
该模式是指:发送者期望向一组接收者发送不被答复的消息。
面向多个接收者的“fire-and-forget”模式是面向单个接收者的“fire-and-forget”模式的扩展。在该模式下,需要将同一个SOAP消息发送给多个SOAP接收者。消息的传输可以使用广播分发技术来实现,当然前提是底层传输协议层支持这一技术。
(3)、其他高级消息交换模式
** 会话模式
基于会话的消息交换模式下,会话的双方将进行一个长时间的会话进程,其中包含多次消息交换。这种进程的例子有复杂的供应链管理、动态的生产日程安排或者是信息修复等。
** 异步的消息模式
在异步消息模式下,发送者以异步方式将消息发往接收者,同时期望在一段时间之后获取一些响应。其中发送者给请求分配了一个标识,并标注了这个请求,这样接收者的响应就可以利用这个标识与初始请求进行关联;同时,发送者也可以为请求分配属于其他服务的一个标识,而这个服务就是最终响应的接收者,也就是说,响应并不一定发回给发送者。
** 多消息异步响应模式
在多消息异步响应模式下,应用程序以异步方式向服务器发送请求消息,依据请求而给出的返回结果将在一段时间之后以多个响应消息的形式返回。这种应用模式常常在被请求的信息无法一次被完整提供而又要保证较好的系统性能的场合下使用。比如在分布式Web搜索这样的场合下应用。
** 事件通知模式
在事件通知模式下,应用程序向一个事件源订阅了一些具有明确名称的事件通知。当被订阅的事件发生时,如果通知发送给最初发出订阅的应用程序的话,那么这种订阅称为单方订阅,如果通知发送给其他应用程序的话,那么这种订阅称为第三方订阅。
(4)、增量解析和处理模式
SOAP消息的增量解析和处理模式,要求发送者具备增量发送的能力,接收者具备增量接收的能力。
这种方法对于内存有限的SOAP处理器而言特别有效,对于那些面向增量的实时数据传输服务而言也非常有效。
如果SOAP Body包含大量的数据,同时在具体应用中适合分段处理,那么通过SAX解析器采用增量处理模式是非常符合需求的。如果SOAP请求是以流(stream)方式传输并增量处理的话,那么相应的响应消息也可以以流的方式传给最初的请求发送者。在这样的应用实例中,我们要格外重视接收方应用的实时性和错误处理方面的设计。如果SOAP请求的Header条目引发错误的话,那么SOAP Fault将被插入到响应消息中,同时请求消息的处理也同时被中止。
(5)、缓存模式
在缓存(caching)模式下,一些应用程序因为效率上的原因,要进行缓存操作。因此需要在响应的环境中设置缓存机制。
缓存机制经常在分布式系统中作为优化机制使用,它可以用于避免重复执行相同的计算操作,或是避免当结果集在一段时间内重复执行复杂的数据库访问,从而节约系统开销。此外,应用了缓存机制之后,数据的副本可以存储在叶节点服务器以方便本地的服务,而无需重复访问中央信息库。如此一来,不仅加快了对信息的访问速度,同时缩减了对网络带宽的占用,而且减轻了中央服务器的负载。
5、SOAP编码类型及规则
(1)、SOAP类型编码规则
介绍几个术语:
** “value”(值)是一个字符串(string)、一个可量度对象(数字、日期、枚举)的名字或是数个简单值的组合。所有的值都有明确地类型。
** “simple value”(简单值) 是一个不可分的值,它不包含任意可以命名的部分。特定的字符串、证书或枚举值等都可以看作简单值。
** “compound value”(复合值) 是一个值的关系的聚集。复合值的例子有特定的采购订单、存货报表、街道地址等。
** 存取标识,在一个复合值中,每一个相关的值都可以用一个角色名来区分,也可以用一个序数来区分,当然也可以同时使用两者。数组也是复合值。它可以被看成是具有多个相同名字的存取标识的复合值,例如RDF。
** “array”(数组) 是一个复合值,在其成员值之间只是顺序位置不同。
** “struct”(结构)是一个复合值,在其成员值之间是依靠存取标识来区分的,同时所有存取标识的名应不同。
** “simple type”(简单类型)是一个简单值的类。简单类型的例子包括“string”类、“integer”类、枚举类等。
** “compound type”(复合类型)是复合值的类。复合类型的例子包括采购订单的抽象类型,这些由该类型派生的采购订单具有相同的存取标识(shipTo、totalCost等),当然它们有不同的值。
** 在一个复合类型中,存取标识在该复合类型中是唯一的,如果它和其他复合类型中的某个存取标识无法相区别,则该存取标识名加上复合类型的名字才能成为唯一标识,这个名称为“局部名”。无论该名是直接或间接基于一个URI,如果该存取标识不用加类型名约束就已经是唯一的,那该名就成为“全局名”。
** 如果只有一个存取标识能够引用一个值,那么称为单引用。如果能被多个存取标识引用,无论是事实上还是潜在可能,那就是多引用。注意,在一个模式中可能有一个确定的值是单引用,而其他值则是多引用。
** 在句法上,一个元素可以是“独立的”或“嵌入的”。一个独立的元素是作为编序中一个顶级元素出现。而其他元素则是嵌入元素。
SOAP的编码规则如下:
** 所有的值都应该表现为元素的内容(content)。一个多引用的值必须被表示为一个独立元素的内容。
** 对每个包含一个值的元素,值的类型表示必须满足以下至少一个条件:(1)、包含该值的元素实例包含一个xsi:type属性,(2)、包含该值的元素实例包含在一个具备enc:arrayType属性的元素中(可能是被设置成default的),(3)、该元素的名字带有一个明确地类型关联,而该类型有一个模式来决定。
** 一个简单值应该表示为字符数据,也就是说,没有任何子元素。每一个简单值必须有一个类型,该类型可以在XML Schema规范的DataTypes部分中列出,也可以在该部分中列出它的源类型。
** 一个复合值应当被编码为一个元素序列,其中每一个存取标识由一个嵌入元素来表示,它们呢的名字是一一对应的。若存取标识的名字在包含它的类型中是局部的,则它的元素名可以不加修饰,而其他则应有完全修饰的元素名。
** 一个多引用的简单或复合值应当被编码为一个独立元素,该独立元素应包含一个局部的带有非限制名的“id”属性,该属性的类型为XML规范中定义的ID类型。对该值的每一个存取标识是一个空元素,该空元素有一个局部的未加修饰的属性“href”,该属性类型是XML Schema规范中定义的“uri-reference”类型,“href”属性的值是一个引用该对应独立元素的URI片段标识。
** 字串和字节数字表示为多引用简单类型,不过还有一些特殊的规则来使它们在通常情况下更有效地表示。一个字串或字节数组的存取标识可以有一个在XML规范中定义的名为“id”的ID类型的属性。如果这样的话,所有其他对该值的存取标识可以被编码为一个空元素,该空元素应包含一个局部的带有非限制名的“href”属性,该属性的类型为 XML Schema规范中定义的“uri-reference”类型,“href”属性的值是一个引用该对应独立元素的URI片段标识。
** 可以给一个值编码多个引用,看上去这些引用是引用了多个不同的值,但从上下文中可知道该XML实例的含义是不变的。
** 数组是复合值。SOAP数组被定义为类型是“enc:Array” 或类型是源于“enc:Array”。
** NULL值和默认值可以在存取标识元素中省略。NULL值可以在一个存取标识元素中使用一个值为1的属性xsi:null 来指明,或者可以是其他依赖于应用程序的属性和值。