使用Ajax调用SOAPWeb服务.docx
- 文档编号:25263069
- 上传时间:2023-06-06
- 格式:DOCX
- 页数:17
- 大小:63.41KB
使用Ajax调用SOAPWeb服务.docx
《使用Ajax调用SOAPWeb服务.docx》由会员分享,可在线阅读,更多相关《使用Ajax调用SOAPWeb服务.docx(17页珍藏版)》请在冰豆网上搜索。
使用Ajax调用SOAPWeb服务
Ajax已普遍用于许多知名的Web应用程序服务,例如GMail、GoogleMaps、Flickr和O。
通过使用异步XML消息传递,Ajax为Web开发人员提供了一种扩展其Web应用程序价值和功能的途径。
这里介绍的WebServicesJavaScriptLibrary扩展了该基础机制,其通过引入对调用基于SOAP的Web服务的支持来增强Ajax设计模式。
从浏览器中调用Web服务
请访问Ajax技术资源中心,这是有关Ajax编程模型信息的一站式中心,包括很多文档、教程、论坛、blog、wiki和新闻。
任何新信息都能在这里找到。
从Web浏览器中调用SOAPWeb服务可能会比较麻烦,这是因为大多数流行的Web浏览器在生成和处理XML方面都略有不同。
所有浏览器都一致实现且用于XML处理的标准API或功能少之又少。
浏览器实现人员一致支持的机制之一是XMLHttpRequestAPI,它是Ajax设计模式的核心。
developerWorks网站最近发布的另一篇由PhilipMcCarthy撰写的的文章详细介绍了该API。
XMLHttpRequest是一个用于执行异步HTTP请求的JavaScript对象。
PhilipMcCarthy在其文章中描述了一个顺序图(请参见图1),此图对于理解XMLHttpRequest对象如何支持Ajax设计非常有帮助(请参阅参考资料,以获得指向全文的链接)。
图1.PhilipMcCarthy的Ajax顺序图
从此图中,您可以清楚地看到XMLHttpRequest对象是如何工作的。
一些运行在Web浏览器内的JavaScript创建了一个XMLHttpRequest实例和一个用于异步回调的函数。
然后,该脚本使用XMLHttpRequest对象对服务器执行HTTP操作。
在接收到响应后,调用回调函数。
在该回调函数内,可能处理返回的数据。
如果返回的数据碰巧是XML,则XMLHttpRequest对象将自动使用浏览器中内置的XML处理机制来解析该数据。
遗憾的是,使用Ajax方法的主要难题在于XMLHttpRequest对象自动解析XML的详细过程。
例如,假设我正在请求的数据是一个SOAP信封,其包含来自许多不同XML命名空间的元素,并且我希望提取yetAnotherElement中属性attr的值。
(请参见清单1)
清单1.一个包含多个命名空间的SOAP信封
Envelope xmlns: s="http: //schemas.xmlsoap.org/soap/envelope/" xmlns: xsd="http: //www.w3.org/2001/XMLSchema" xmlns: xsi="http: //www.w3.org/2001/XMLSchema-instance"> Header/> Body> someElementxmlns: m="http: //example"> someOtherElement xmlns: n="http: //example" xmlns: m="urn: example"> yetAnotherElement n: attr="abc" xmlns: n="urn: foo"/> someOtherElement> someElement> Body> Envelope> 在Mozilla浏览器和Firefox浏览器中,提取attr属性值非常简单,如清单2所示。 清单2.在Mozilla和Firefox中检索attr属性值的方法不能运用在InternetExplorer中 varm=el.getElementsByTagNameNS( 'urn: example', 'yetAnotherElement')[0]. getAttributeNS( 'urn: foo', 'attr'); alert(m);//displays'abc' 关于安全性 由于涉及许多实际安全问题,因此在缺省情况下,大多数Web浏览器中的XMLHttpRequest对象都限制为只能与用户正在查看的Web页所在的域中承载的资源和服务进行交互。 例如,如果我正在访问一个位于的页面,则XMLHttpRequest将只允许访问位于域中的资源。 对于阻止恶意应用程序代码潜在地对其不应该访问的信息进行不适当的访问,这种预防措施非常必要。 因为这里介绍的Web服务客户机基于XMLHttpRequest,所以这种限制同样适用于您将会调用的Web服务。 如果您需要能够访问位于另一个域中的Web服务,您可以使用以下两种合理的解决方案: ∙对JavaScript进行数字签名。 通过对JavaScript脚本进行数字签名,您就告诉了Web浏览器可以信任该脚本不会执行任何恶意的活动,并且对XMLHttpRequest可以访问的数据的限制也应该取消。 ∙使用代理。 一个简单的解决方案是,通过位于加载的页面所在的域中的代理资源来传递所有来自XMLHttpRequest的请求。 该代理将XMLHttpRequest的请求转发到远程位置,并将结果返回给浏览器。 从XMLHttpRequest对象的角度来看,这种交互发生在现有的安全配置之内。 遗憾的是,以上代码无法在InternetExplorerVersion6中运行,因为该浏览器不仅没有实现getElementsByTagNameNS功能,而且事实上还使用了一种很糟糕的方法——将XML命名空间的前缀作为其元素和属性名称的一部分来对待。 InternetExplorer缺少对XML命名空间的支持,这使得它很难处理命名空间密集的XML格式,例如采用独立于浏览器的方式的SOAP。 即使要执行一些像提取结果中的属性值这样简单的操作,您也必须编写能够在多个浏览器中实现一致预期行为的特殊代码。 幸运的是,这种特殊代码可以封装并重用。 为了从Web浏览器中调用Web服务,并可靠地处理SOAP消息,您需要首先了解一些安全问题(请参见侧栏“关于安全性”)。 此外,您还需要编写一个JavaScript脚本库(图2),以便将底层浏览器XML实现中的不一致情况抽象出来,从而使您能够直接处理Web服务数据。 图2.在使用WebServicesJavaScriptLibrary的Web浏览器中通过Javascript调用Web服务 图2中的WebServicesJavaScriptLibrary(ws.js)是一组JavaScript对象和实用功能,它们为基于SOAP1.1的Web服务提供了基本的支持。 Ws.js定义了下列对象: ∙WS.Call: 一个包装了XMLHttpRequest的Web服务客户机 ∙WS.QName: XML限定名实现 ∙WS.Binder: 自定义XML序列化器/反序列化器的基础 ∙WS.Handler: 请求/响应处理程序的基础 ∙SOAP.Element: 包装了XMLDOM的基本SOAP元素 ∙SOAP.Envelope: SOAPEnvelope对象扩展了SOAP.Element ∙SOAP.Header: SOAPHeader对象扩展了SOAP.Element ∙SOAP.Body: SOAPBody对象扩展了SOAP.Element ∙XML: 用于处理XML的跨平台实用方法 ws.js的核心是WS.Call对象,该对象提供了调用Web服务的方法。 WS.Call主要负责与XMLHttpRequest对象进行交互,并处理SOAP响应。 WS.Call对象公开了以下三个方法: ∙add_handler。 向处理链添加请求/响应处理程序。 处理程序对象在调用Web服务的前后被调用,以支持可扩展的预调用处理和后调用处理。 ∙invoke。 将指定的SOAP.Envelope对象发送给Web服务,然后在接收到响应后调用回调函数。 当调用使用文本XML编码的文档样式的Web服务时,请使用此方法。 ∙invoke_rpc。 创建一个封装RPC样式请求的SOAP.Envelope,并将其发送到Web服务。 当接收到响应时,调用回调函数。 在通常情况下,WS.Call对象只不过是位于XMLHttpRequest对象顶层的瘦包装器(thinwrapper),该包装器能够执行许多简化处理的操作。 这些操作包括设置SOAP1.1规范要求的SOAPActionHTTPHeader。 使用ws.js WebservicesJavaScriptLibrary提供的API非常简单。 SOAP.*对象(SOAP.Element、SOAP.Envelope、SOAP.Header和SOAP.Body)提供了构建和读取SOAP信封的方法,如清单3所示,因而处理XML文档对象模型的底层细节就顺利地抽象出来。 清单3.构建一个SOAP信封 varenvelope=newSOAP.Envelope(); varbody=envelope.create_body(); varel=body.create_child(newWS.QName('method','urn: foo')); el.create_child(newWS.QName('param','urn: foo')).set_value('bar'); 清单4显示了由清单3中的代码生成的SOAP信封。 清单4.构建一个SOAP信封 //schemas.xmlsoap.org"> foo"> bar 如果您正在创建的SOAP信封代表一个RPC样式的请求,则SOAP.Body元素提供了一个简便方法set_rpc(如清单5所示),该方法能够构造一个完整的RPC请求——包含一个指定的操作名称、一个指定的输入参数数组和一个SOAP编码样式的URI。 清单5.构建一个RPC请求信封 varenvelope=newSOAP.Envelope(); varbody=envelope.create_body(); body.set_rpc( newWS.QName('param','urn: foo'), newArray( {name: 'param',value: 'bar'} ),SOAP.NOENCODING ); 每个参数都作为一个JavaScript对象结构进行传递,且可能带有以下属性: ∙name。 一个指定参数名称的字符串或WS.QName对象。 必需。 ∙value。 参数的值。 如果该值不是一个简单数据类型(例如,字符串、整数或其他),则应该指定一个能将该值序列化为适当的XML结构的WS.Binder。 必需。 ∙xsitype: 标识参数的XML模式实例类型的WS.QName(例如,xsi: type="int"对应xsitype: newWS.QName('int','http: //www.w3.org/2000/10/XMLSchema'))。 可选。 ∙encodingstyle: 标识参数所使用的SOAP编码样式的URI。 可选。 ∙binder: 能够将参数序列化为XML的WS.Binder实现。 可选。 例如,如果要指定的参数名为“abc”、XML命名空间为“urn: foo”、xsi: type为“int”且值为“3”,则我会使用以下代码: newArray({name: newWS.QName('abc','urn: foo'),value: 3,xsitype: newWS.QName('int','http: //www.w3.org/2000/10/XMLSchema')})。 一旦我为服务请求构建了SOAP.Envelope,我就会将该SOAP.Envelope传递到WS.Call对象的invoke方法,以便调用该信封内编码的方法: (newWS.Call(service_uri)).invoke(envelope,callback) 另一种可选方案是手动构建SOAP.Envelope。 我会将参数WS.QName、参数数组和编码样式传递到WS.Call对象的invoke_rpc方法,如清单6所示。 清单6.使用WS.Call对象调用Web服务 varcall=newWS.Call(serviceURI); varnsuri='urn: foo'; varqn_op=newWS.QName('method',nsuri); varqn_op_resp=newWS.QName('methodResponse',nsuri); call.invoke_rpc( qn_op, newArray( {name: 'param',value: 'bar'} ),SOAP.NOENCODING, function(call,envelope){ //envelopeistheresponseSOAP.Envelope //theXMLTextoftheresponseisinarguments[2] } ); 在调用invoke方法或invoke_rpc方法时,WS.Call对象会创建一个基本的XMLHttpRequest对象,用包含SOAP信封的XML元素进行传递,并接收和解析响应,然后调用提供的回调函数。 为了能够扩展SOAP消息的预处理和后处理,WS.Call对象允许您注册一组WS.Handler对象,如清单7所示。 对于调用周期内的每个请求、每个响应和每个错误,都将调用这些对象。 可以通过扩展WS.HandlerJavaScript对象来实现新的处理程序。 清单7.创建和注册响应/响应处理程序 varMyHandler=Class.create(); MyHandler.prototype=(newWS.Handler()).extend({ on_request: function(envelope){ //pre-requestprocessing }, on_response: function(call,envelope){ //post-response,pre-callbackprocessing }, on_error: function(call,envelope){ } }); varcall=newWS.Call(...); call.add_handler(newMyHandler()); 处理程序对插入或提取正在传递的SOAP信封中的信息最有用。 例如,您可以设想一个处理程序自动向SOAPEnvelope的Header插入适当的Web服务寻址(WebServicesAddressing)元素,如清单8中的示例所示。 清单8.一个将Web服务寻址操作Header添加到请求中的处理程序示例 varWSAddressingHandler=Class.create(); WSAddressingHandler.prototype=(newWS.Handler()).extend({ on_request: function(call,envelope){ envelope.create_header().create_child( newWS.QName('Action','http: //ws-addressing','wsa') ).set_value(''); } }); WS.Binder对象(清单9)执行SOAP.Element对象的自定义序列化和反序列化。 WS.Binder的实现必须提供以下两个方法: ∙to_soap_element。 将JavaScript对象序列化为SOAP.Element。 传入的第一个参数是要序列化的值。 第二个参数是SOAP.Element,必须将要序列化的值序列化为SOAP.Element。 该方法不返回任何值。 ∙to_value_object。 将SOAP.Element反序列化为JavaScript对象。 该方法必须返回反序列化的值对象。 清单9.WS.Binding实现示例 varMyBinding=Class.create(); MyBinding.prototype=(newWS.Binding()).extend({ to_soap_element: function(value,element){ ... }, to_value_object: function(element){ ... } }); 一个简单示例 我已经提供了一个示例项目来阐释WebServicesJavaScriptLibrary的基本功能。 该演示所使用的Web服务(如清单10所示)已经在WebSphereApplicationServer中进行了实现,并提供了简单的HelloWorld功能。 清单10.一个简单的基于Java的“HelloWorld”Web服务 packageexample; publicclassHelloWorld{ publicStringsayHello(Stringname){ return"Hello"+name; } } 在实现了该服务并将其部署到WebSphereApplicationServer后,该服务(清单11)的WSDL描述定义了您需要传递的SOAP消息(用于调用HelloWorld服务)。 清单11.HelloWorld.wsdl的代码片段 portTypename="HelloWorld"> operationname="sayHello"> input message="impl: sayHelloRequest" name="sayHelloRequest"/> output message="impl: sayHelloResponse" name="sayHelloResponse"/> operation> portType> 通过使用WebServicesJavaScriptLibrary,您可以实现一个调用HelloWorld服务的方法,如清单12所示。 清单12.使用WS.Call调用HelloWorld服务 ... functionsayHello(name,container){ varcall=newWS.Call('/AjaxWS/services/HelloWorld'); varnsuri='http: //example'; varqn_op=newWS.QName('sayHello',nsuri); varqn_op_resp=newWS.QName('sayHelloResponse',nsuri); call.invoke_rpc( qn_op, newArray( {name: 'name',value: name} ),null, function(call,envelope){ varret= envelope.get_body().get_all_children()[0]. get_all_children()[0].get_value(); container.innerHTML=ret; $('soap').innerHTML=arguments[2].escapeHTML(); } ); } ... 然后,您可以在我们的Web应用程序中的任意位置通过调用sayHello函数来调用HelloWorld服务。 请参见清单13。 清单13.调用sayHello函数 type="button" onclick="sayHello($('name').value,$('result'))"/>
调用成功后的结果如图3所示。
在Mozilla、Firefox和InternetExplorer中运行该示例应该会得到相同的结果。
图3.Firefox中的HelloWorld示例
后续部分
使用WebServicesJavaScriptLibrary,可以采用简单的独立于浏览器的方式将基本的SOAPWeb服务合并到Web应用程序中。
在本系列的下一个部分中,您不仅可以探讨如何使用该库来调用更多基于Web服务资源框架(WS-ResourceFramework)
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 使用 Ajax 调用 SOAPWeb 服务