使用Asynchronous JavaScript and XML(Ajax)设计模式实现基于Web浏览器的SOAP Web服务。在本系列的第1部分“使用Ajax调用SOAP Web服务,第1部分”中,作者引入了一个简单的用于调用SOAP Web服务的基于Web浏览器的JavaScript库。在接下来的讨论中,作者将实现对Web服务寻址语言(Web Services Addressing Language)和Web服务资源框架(Web Services Addressing Language)规范的支持,以便扩展JavaScript库的功能。
概述
在本系列的第1部分,我介绍了一个跨浏览器的JavaScript库,其中提供了一个简单的SOAP Web服务客户机,该客户机可以发出采用RRC编码和文档-文本样式的请求。该客户机包含对请求和响应处理程序、自定义XML序列化器/反序列化器以及SOAP Header的支持;所有这些支持都将在这个WS-Addressing和WS-ResourceFramework实现中用到。
ws.js(在第1部分中引入的)中定义的主要对象包括:
·WS.Call:包装XMLHttpRequest的Web服务客户机
·WS.QName:XML限定名称实现
·WS.Binder:自定义XML序列化器/反序列化器的基对象
·WS.Handler:请求/响应处理程序的基对象
·SOAP.Element:包装XML DOM的基本SOAP元素
·SOAP.Envelope:扩展自SOAP.Element的SOAP Envelope对象
·SOAP.Header:扩展自SOAP.Element的SOAP Header对象
·SOAP.Body:扩展自SOAP.Element的SOAP Body对象
·XML:用于处理XML的跨平台实用方法
这一组对象中有五个对象对WS-Addressing和WS-ResourceFramework实现非常关键:WS.QName、SOAP.Element、WS.Handler、WS.Binder和WS.Call。我强烈建议重新阅读一下第一篇文章,以回顾这些对象的基本功能。
在本文中,我将引入两个新的JavaScript文件。第一个文件定义支持WS-Addressing的对象(wsa.js);而第二个文件定义支持WS-ResourceFramework的基本实现的对象(wsrf.js)。
图1. 从Web浏览器内使用Web服务JavaScript库调用Web服务资源框架服务
wsa.js中定义的主要对象包括:
·WSA.EndpointReference:WS-Addressing EndpointReference对象。
·WSA.EndpointReference.ReferenceParameters:WS-Addressing EPR引用参数的容器。
·WSA.EndpointReference.Binder:WSA.EndpointReference对象的XML序列化器/反序列化器。
·WSA.MessageContext:WS-Addressing SOAP消息Header元数据的容器。
·WSA.Handler:将WS-Addressing SOAP消息Header插入SOAP信封的请求处理程序。
wsrf.js中定义的主要对象包括:
·WSRF.Request.GetResourceProperty:WS-ResourceFramework GetResourceProperty操作的包装对象。
·WSRF.Request.GetMultipleResourceProperties:WS-ResourceFrame GetMultipleresourceProperties操作的包装对象。
·WSRF.Resource:用于调用WS-ResourceFramework操作的客户机接口。
请注意,虽然这可能意味着要了解大量的新JavaScript对象,但它们所提供的API都经过了专门设计,以尽可能减少在实际调用Web服务时必须进行的工作量。例如,如果您跳到清单8,您将发现,通过使用API,您只需使用寥寥数行代码即可调用与WS-ResourceFramework兼容的Web服务中的方法–而无需受底层SOAP实现细节的困扰。
实现WS-Addressing支持
Web服务寻址规范定义了用于向SOAP信封插入寻址信息的机制。WS-Addressing的核心是一个称为EndpointReference的对象,该对象可作为对特定Web服务实例的引用和说明。(请参见清单1。)除了EndpointReference之外,WS-Addressing规范还定义了许多SOAP消息Header,可以将其用于直接在SOAP信封中传递寻址信息。
wsa.js JavaScript库提供了许多实现了对WS-Addressing EndpointReference和SOAP消息Header元素的基本支持的对象。
清单1. 一个简单的WS-Addressing EndpointReference
<EndpointReference >
<Address>http://www.example.org/services/HelloWorld</Address>
<ReferenceParameters>
<abc:foo >This is a test</abc:foo>
</ReferenceParameters>
</EndpointReference>
WSA.EndpointReference对象用于表示WS-Addressing EndpointReference,如清单2中所示。通过将此代码与上面的XML进行比较,您应当能够很好地理解API的操作方式。
清单2. 创建与WSA.js相关的EndpointReference
var epr =
new WSA.EndpointReference(
“http://www.example.org/services/HelloWorld”);
var epr_rp = epr.create_reference_parameters();
epr_rp.create_child(
new WS.QName(’foo’,’urn:foo’,’abc’)).
set_value(’This is a test’);
WSA.EndpointReference的API目前支持WS-Addressing信息模型所定义的Address和ReferenceParameters属性。目前尚未实现Metadata属性,因为这个属性对于此处实现的客户机基本功能并不重要。
WS-Addressing SOAP消息Header应该设置在Web服务客户机发送给服务的SOAP信封上。由于在ws.js JavaScript库中定义的WS.Call对象将隐藏使用底层SOAP信封的细节,因此请使用WS.Handler来为您插入恰当的Header。
Web服务客户机将针对每个请求、响应和错误调用WS.Handler对象的各个方法。对于WS-Addressing实现,提供了一个WSA.Handler,以使用相应的WSA.MessageContext对象(其中包含要插入到消息中的信息)。清单3演示了这一过程。
清单3. 使用WS-Addressing上下文和处理程序
var address = ’http://www.example.com/services/HelloWorld’;
var ctx = new WSA.MessageContext();
ctx.to = new WSA.EndpointReference(address);
ctx.replyto = new WSA.EndpointReference(WSA.ANONYMOUS);
ctx.action = address + ’#SayHello’
var handler = new WSA.Handler();
handler.set_context(ctx);
var call = new WS.Call(’’);
call.add_handler(handler);
WSA.MessageContext对象中的属性与每个WS-Addressing SOAP消息Header相对应:
·to:一个WSA.EndpointReference对象,其Address指定表示信息目的地的绝对URI。
·from:一个WSA.EndpointReference对象,标识消息的发送方。
·replyto:一个WSA.EndpointReference对象,标识回复应送达的位置。
·faultto:一个WSA.EndpointReference对象,标识错误应送达的位置。
·action:一个绝对URI,标识消息应触发的操作。
·messageid:唯一标识消息的绝对URI。
·relatesto:标识相关消息的URI对的数组。URI对中的第一个URI标识关系类型;第二个URI指定相关消息的唯一Message ID。
WSA.Handler向用于调用Web服务的WS.Call对象进行了注册后,WS.Call对象就会在每次请求时调用该处理程序,向其传递对SOAP.Envelope对象的引用。处理程序将从WSA.MessageContext中提取信息,并向消息中插入恰当的Header,如清单5中所示。
实现WS-ResourceFramework支持
Web服务资源框架定义了一个使用Web服务标准访问和操作有状态资源的实例的约定。各个资源均使用WS-Addressing EndpointReference进行标识和引用。可以使用一些常见操作来检索或修改资源的属性。
wsrf.js JavaScript库提供了支持GetResourceProperty和GetMultipleResourceProperties操作的部分Web服务资源框架实现。该API是以ws.js和wsa.js API为基础构建的,主要是为了演示这两个脚本的使用而设计的,而不是为了提供全面的WS-ResourceFramework实现。
WS-ResourceFramework操作是定向到特定Resource实例的文档-文本SOAP请求。目标资源是用WS-Addressing EndpointReference标识的,如清单4所示。
清单4. WSRF EndpointReference
<EndpointReference >
<Address>http://localhost:9080/SoapAjax2/services/DeviceService</Address>
<ReferenceParameters>
<abc:DeviceID >ABC123</abc:DeviceID>
</ReferenceParameters>
</EndpointReference>
当使用wsa.js中定义的机制在SOAP内进行表示时,WSRF EndpointReference中的信息将以SOAP消息Header的形式出现,如清单5中所示。
清单5. WSRF GetResourceProperty请求
<Envelope >
<Header>
<To >
http://localhost:9080/SoapAjax2/services/DeviceService</To>
<abc:DeviceID >ABC123</abc:DeviceID>
</Header>
<Body>
<GetResourceProperty
>ns:bar</GetResourceProperty>
</Body>
</Envelope>
wsrf.js提供的API用于隐藏使用SOAP Envelope的所有细节以及允许与WS-ResourceFramework Web服务交互所必需的WS-Addressing Header。不过,稍微注意一下此代码,您就会发现此代码的工作方式的许多重要方面。
清单6 演示了WSRF GetResourceProperty操作的包装对象。此包装对象由wsrf.js库内部使用,其中包含了创建SOAP信封和构建操作所必需的XML的基本机制。请注意,该对象利用了ws.js提供的SOAP.Element和SOAP.Envelope API。在包装对象初始化阶段传入的“qname”参数是所请求的属性的XML限定名称。
清单6. WSRF GetResourceProperty请求包装对象
WSRF.Request.GetResourceProperty = Class.create();
WSRF.Request.GetResourceProperty.prototype = {
initialize : function(qname) {
this.envelope = new SOAP.Envelope();
this.set_qname(qname);
},
set_qname : function(qname) {
var body = this.envelope.create_body();
var method = body.create_child(
WSRF.Request.QNAME_GETRESOURCEPROPERTY);
if (!qname.namespace) qname.namespace = ’’;
if (!qname.prefix) qname.prefix = ’ns’;
method.declare_namespace(qname);
method.set_value(qname.value_of());
}
};
清单7中包含了来自WSRF.Resource对象的代码片段。您所看到的代码的作用在于:创建WS.Call对象,准备将用于设置恰当的SOAP消息Header的WSA.Handler对象,创建WSRF.Request.GetResourceProperty包装对象以及调用各个Web服务操作。
清单7. 调用WSRF GetResourceProperty
get_resource_property : function(qname, callback) {
var call = new WS.Call(this.address);
var handler = new WSA.Handler();
var wsactx = new WSA.MessageContext(this.epr);
handler.set_context(wsactx);
call.add_handler(handler);
var req = new WSRF.Request.GetResourceProperty(qname);
call.invoke(req.envelope, callback);
}
为了对WS-ResourceFramework Web调用GetResourceProperty操作,应用程序只需要提供目标WS-Resource的EndpointReference和标识被检索的属性的WS.QName对象即可,如清单8中所示。
清单8. 最终结果
var ADDRESS = ’http://localhost:9080/SoapAjax2/services/DeviceService’
function getDeviceName(deviceID, container) {
var epr = new WSA.EndpointReference(ADDRESS);
var epr_rp = epr.create_reference_parameters();
epr_rp.create_child(
new WS.QName(
’DeviceID’,
’urn:deviceservice’)).set_value(deviceID);
var res = new WSRF.Resource(ADDRESS, epr);
res.get_resource_property(
new WS.QName(’DeviceName’,’urn:deviceservice’),
function(call,envelope) {
$(’soap’).innerHTML = arguments[2].escapeHTML();
}
);
}
清单8将对WS-Resource的调用包装在可以从HTML页中的任何位置调用的适当函数中。清单9提供了一个按钮,该按钮可以从名为id的输入字段传入一个设备ID,并在名为result的元素中显示响应SOAP信封。
清单9. 调用getDeviceName
<input
value=”Invoke the Web Service”
type=”button”
onclick=”getDeviceName($(’id’).value,$(’result’))” />
后续部分
在这一部分中,您了解了在本系列第1部分中引入的Ajax Web服务客户机可以如何进行扩展,以支持更高级的Web服务标准(如Web服务寻址和Web服务资源框架)。在下一部分中,作者将讨论对Web服务描述语言(Web Services Description Language)的支持。
我们一直都在努力坚持原创.......请不要一声不吭,就悄悄拿走。
我原创,你原创,我们的内容世界才会更加精彩!
【所有原创内容版权均属TechTarget,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用。】
微信公众号
TechTarget
官方微博
TechTarget中国
作者
相关推荐
-
AWS MEAN堆栈+JavaScript=快速搭建应用
开发人员在构建Web应用时有许多选择。市面上有无数的框架和语言可选,而像AWS这样的云平台可以方便地部署和扩展应用程序。
-
JDK 8u40更新:新增功能抢先看
俗话说长江后浪推前浪,一代新人换旧人,Java更新版本交替,也是这样一个道理。甲骨文又给Java添加了哪些新功能。
-
移动浏览器到云:JavaScript地位正在扩张
不难发现人们非常喜欢在前端开发中使用JavaScript。但是,令我们惊讶的是后端开发也如此青睐JavaScript,促进了基于云和基于数据中心的托管应用的发展。
-
移动HTML5挑战何在?
当HTML5出现时,许多开发者和应用架构师视之为创建平台独立应用、简化你的设备支持以及当新的移动设备OS版本发布时减少应用相关问题的机会。