<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Vincent.Chan‘s Blog

    常用鏈接

    統(tǒng)計

    積分與排名

    網(wǎng)站

    最新評論

    使用 AJAX 調(diào)用 SOAP Web 服務(wù),第 1 部分: 構(gòu)建 Web 服務(wù)客戶機

    級別: 中級

    James Snell, 軟件工程師, IBM

    2006 年 1 月 16 日

    本文介紹如何使用異步 JavaScript 和 XML (Asynchronous JavaScript and XML, AJAX) 設(shè)計模式來實現(xiàn)基于 Web 瀏覽器的 SOAP Web 服務(wù)客戶機。

    本文是一篇短的系列文章的第 1 部分,演示了如何使用針對 Web 應(yīng)用程序的 AJAX 設(shè)計模式來實現(xiàn)跨平臺的基于 JavaScript 的 SOAP Web 服務(wù)客戶機。

    AJAX 已普遍用于許多知名的 Web 應(yīng)用程序服務(wù),例如 GMail、Google Maps、Flickr 和 Odeo.com。通過使用異步 XML 消息傳遞,AJAX 為 Web 開發(fā)人員提供了一種擴展其 Web 應(yīng)用程序價值和功能的途徑。這里介紹的 Web Services JavaScript Library 擴展了該基礎(chǔ)機制,其通過引入對調(diào)用基于 SOAP 的 Web 服務(wù)的支持來增強 AJAX 設(shè)計模式。

    從瀏覽器中調(diào)用 Web 服務(wù)

    從 Web 瀏覽器中調(diào)用 SOAP Web 服務(wù)可能會比較麻煩,這是因為大多數(shù)流行的 Web 瀏覽器在生成和處理 XML 方面都略有不同。所有瀏覽器都一致實現(xiàn)且用于 XML 處理的標(biāo)準(zhǔn) API 或功能少之又少。

    瀏 覽器實現(xiàn)人員一致支持的機制之一是 XMLHttpRequest API,它是 AJAX 設(shè)計模式的核心。developerWorks 網(wǎng)站最近發(fā)布的另一篇由 Philip McCarthy 撰寫的的文章詳細(xì)介紹了該 API。XMLHttpRequest 是一個用于執(zhí)行異步 HTTP 請求的 JavaScript 對象。Philip McCarthy 在其文章中描述了一個順序圖(請參見圖 1),此圖對于理解 XMLHttpRequest 對象如何支持 AJAX 設(shè)計非常有幫助(請參閱參考資料,以獲得指向全文的鏈接)。


    圖 1. Philip McCarthy 的 AJAX 順序圖
    Philip McCarthy 的 AJAX 順序圖

    從 此圖中,您可以清楚地看到 XMLHttpRequest 對象是如何工作的。一些運行在 Web 瀏覽器內(nèi)的 JavaScript 創(chuàng)建了一個 XMLHttpRequest 實例和一個用于異步回調(diào)的函數(shù)。然后,該腳本使用 XMLHttpRequest 對象對服務(wù)器執(zhí)行 HTTP 操作。在接收到響應(yīng)后,調(diào)用回調(diào)函數(shù)。在該回調(diào)函數(shù)內(nèi),可能處理返回的數(shù)據(jù)。如果返回的數(shù)據(jù)碰巧是 XML,則 XMLHttpRequest 對象將自動使用瀏覽器中內(nèi)置的 XML 處理機制來解析該數(shù)據(jù)。

    遺憾的是,使用 AJAX 方法的主要難題在于 XMLHttpRequest 對象自動解析 XML 的詳細(xì)過程。例如,假設(shè)我正在請求的數(shù)據(jù)是一個 SOAP 信封,其包含來自許多不同 XML 命名空間的元素,并且我希望提取 yetAnotherElement 中屬性 attr 的值。(請參見清單 1


    清單 1. 一個包含多個命名空間的 SOAP 信封
    												
    														

    <s: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">
    <s:Header/>
    <s:Body>
    <m:someElement xmlns:m="http://example">
    <n:someOtherElement
    xmlns:n="http://example"
    xmlns:m="urn:example">
    <m:yetAnotherElement
    n:attr="abc"
    xmlns:n="urn:foo"/>
    </n:someOtherElement>
    </m:someElement>
    </s:Body>
    </s:Envelope>

    在 Mozilla 瀏覽器和 Firefox 瀏覽器中,提取 attr 屬性值非常簡單,如清單 2所示。


    清單 2. 在 Mozilla 和 Firefox 中檢索 attr 屬性值的方法不能運用在 Internet Explorer 中
    												
    														

    var m = el.getElementsByTagNameNS(
    'urn:example',
    'yetAnotherElement')[0].
    getAttributeNS(
    'urn:foo',
    'attr');
    alert(m); // displays 'abc'

    關(guān)于安全性

    由 于涉及許多實際安全問題,因此在缺省情況下,大多數(shù) Web 瀏覽器中的 XMLHttpRequest 對象都限制為只能與用戶正在查看的 Web 頁所在的域中承載的資源和服務(wù)進(jìn)行交互。例如,如果我正在訪問一個位于 http://example.com/myapp/ 的頁面,則 XMLHttpRequest 將只允許訪問位于 example.com 域中的資源。對于阻止惡意應(yīng)用程序代碼潛在地對其不應(yīng)該訪問的信息進(jìn)行不適當(dāng)?shù)脑L問,這種預(yù)防措施非常必要。因為這里介紹的 Web 服務(wù)客戶機基于 XMLHttpRequest,所以這種限制同樣適用于您將會調(diào)用的 Web 服務(wù)。

    如果您需要能夠訪問位于另一個域中的 Web 服務(wù),您可以使用以下兩種合理的解決方案:

    • 對 JavaScript 進(jìn)行數(shù)字簽名。通過對 JavaScript 腳本進(jìn)行數(shù)字簽名,您就告訴了 Web 瀏覽器可以信任該腳本不會執(zhí)行任何惡意的活動,并且對 XMLHttpRequest 可以訪問的數(shù)據(jù)的限制也應(yīng)該取消。
    • 使用代理。一 個簡單的解決方案是,通過位于加載的頁面所在的域中的代理資源來傳遞所有來自 XMLHttpRequest 的請求。該代理將 XMLHttpRequest 的請求轉(zhuǎn)發(fā)到遠(yuǎn)程位置,并將結(jié)果返回給瀏覽器。從 XMLHttpRequest 對象的角度來看,這種交互發(fā)生在現(xiàn)有的安全配置之內(nèi)。

    遺 憾的是,以上代碼無法在 Internet Explorer Version 6 中運行,因為該瀏覽器不僅沒有實現(xiàn) getElementsByTagNameNS 功能,而且事實上還使用了一種很糟糕的方法——將 XML 命名空間的前綴作為其元素和屬性名稱的一部分來對待。

    Internet Explorer 缺少對 XML 命名空間的支持,這使得它很難處理命名空間密集的 XML 格式,例如采用獨立于瀏覽器的方式的 SOAP。即使要執(zhí)行一些像提取結(jié)果中的屬性值這樣簡單的操作,您也必須編寫能夠在多個瀏覽器中實現(xiàn)一致預(yù)期行為的特殊代碼。幸運的是,這種特殊代碼可以 封裝并重用。

    為了從 Web 瀏覽器中調(diào)用 Web 服務(wù),并可靠地處理 SOAP 消息,您需要首先了解一些安全問題(請參見側(cè)欄“關(guān)于安全性”)。此外,您還需要編寫一個 JavaScript 腳本庫(圖 2),以便將底層瀏覽器 XML 實現(xiàn)中的不一致情況抽象出來,從而使您能夠直接處理 Web 服務(wù)數(shù)據(jù)。


    圖 2. 在使用 Web Services JavaScript Library 的 Web 瀏覽器中通過 Javascript 調(diào)用 Web 服務(wù)
    在 Web 瀏覽器中通過 Javascript 調(diào)用 Web 服務(wù)

    圖 2 中的 Web Services JavaScript Library (ws.js) 是一組 JavaScript 對象和實用功能,它們?yōu)榛?SOAP 1.1 的 Web 服務(wù)提供了基本的支持。Ws.js 定義了下列對象:

    • WS.Call:一個包裝了 XMLHttpRequest 的 Web 服務(wù)客戶機
    • WS.QName:XML 限定名實現(xiàn)
    • WS.Binder:自定義 XML 序列化器/反序列化器的基礎(chǔ)
    • WS.Handler:請求/響應(yīng)處理程序的基礎(chǔ)
    • SOAP.Element:包裝了 XML DOM 的基本 SOAP 元素
    • SOAP.Envelope:SOAP Envelope 對象擴展了 SOAP.Element
    • SOAP.Header:SOAP Header 對象擴展了 SOAP.Element
    • SOAP.Body:SOAP Body 對象擴展了 SOAP.Element
    • XML:用于處理 XML 的跨平臺實用方法

    ws.js 的核心是 WS.Call 對象,該對象提供了調(diào)用 Web 服務(wù)的方法。WS.Call 主要負(fù)責(zé)與 XMLHttpRequest 對象進(jìn)行交互,并處理 SOAP 響應(yīng)。

    WS.Call 對象公開了以下三個方法:

    • add_handler。向處理鏈添加請求/響應(yīng)處理程序。處理程序?qū)ο笤谡{(diào)用 Web 服務(wù)的前后被調(diào)用,以支持可擴展的預(yù)調(diào)用處理和后調(diào)用處理。
    • invoke。將指定的 SOAP.Envelope 對象發(fā)送給 Web 服務(wù),然后在接收到響應(yīng)后調(diào)用回調(diào)函數(shù)。當(dāng)調(diào)用使用文本 XML 編碼的文檔樣式的 Web 服務(wù)時,請使用此方法。
    • invoke_rpc。創(chuàng)建一個封裝 RPC 樣式請求的 SOAP.Envelope,并將其發(fā)送到 Web 服務(wù)。當(dāng)接收到響應(yīng)時,調(diào)用回調(diào)函數(shù)。

    在 通常情況下,WS.Call 對象只不過是位于 XMLHttpRequest 對象頂層的瘦包裝器 (thin wrapper),該包裝器能夠執(zhí)行許多簡化處理的操作。這些操作包括設(shè)置 SOAP 1.1 規(guī)范要求的 SOAPAction HTTP Header。





    回頁首


    使用 ws.js

    Web services JavaScript Library 提供的 API 非常簡單。

    SOAP.* 對象(SOAP.ElementSOAP.EnvelopeSOAP.HeaderSOAP.Body)提供了構(gòu)建和讀取 SOAP 信封的方法,如清單 3 所示,因而處理 XML 文檔對象模型的底層細(xì)節(jié)就順利地抽象出來。


    清單 3. 構(gòu)建一個 SOAP 信封
    												
    														

    var envelope = new SOAP.Envelope();
    var body = envelope.create_body();
    var el = body.create_child(new WS.QName('method','urn:foo'));
    el.create_child(new WS.QName('param','urn:foo')).set_value('bar');

    清單 4 顯示了由 清單 3 中的代碼生成的 SOAP 信封。


    清單 4. 構(gòu)建一個 SOAP 信封
    												
    														

    <Envelope xmlns="http://schemas.xmlsoap.org">
    <Body>
    <method xmlns="urn:foo">
    <param>bar</param>
    </method>
    </Body>
    </Envelope>

    如果您正在創(chuàng)建的 SOAP 信封代表一個 RPC 樣式的請求,則 SOAP.Body 元素提供了一個簡便方法 set_rpc(如清單 5 所示),該方法能夠構(gòu)造一個完整的 RPC 請求——包含一個指定的操作名稱、一個指定的輸入?yún)?shù)數(shù)組和一個 SOAP 編碼樣式的 URI。


    清單 5. 構(gòu)建一個 RPC 請求信封
    												
    														

    var envelope = new SOAP.Envelope();
    var body = envelope.create_body();
    body.set_rpc(
    new WS.QName('param','urn:foo'),
    new Array(
    {name:'param',value:'bar'}
    ), SOAP.NOENCODING
    );

    每個參數(shù)都作為一個 JavaScript 對象結(jié)構(gòu)進(jìn)行傳遞,且可能帶有以下屬性:

    • name。一個指定參數(shù)名稱的字符串或 WS.QName 對象。必需
    • value。參數(shù)的值。如果該值不是一個簡單數(shù)據(jù)類型(例如,字符串、整數(shù)或其他),則應(yīng)該指定一個能將該值序列化為適當(dāng)?shù)?XML 結(jié)構(gòu)的 WS.Binder。必需
    • xsitype:標(biāo)識參數(shù)的 XML 模式實例類型的 WS.QName(例如,xsi:type="int" 對應(yīng) xsitype:new WS.QName('int','http://www.w3.org/2000/10/XMLSchema'))。可選
    • encodingstyle:標(biāo)識參數(shù)所使用的 SOAP 編碼樣式的 URI。可選
    • binder:能夠?qū)?shù)序列化為 XML 的 WS.Binder 實現(xiàn)。可選

    例如,如果要指定的參數(shù)名為“abc”、XML 命名空間為“urn:foo”、xsi:type 為“int”且值為“3”,則我會使用以下代碼:new Array({name:new WS.QName('abc','urn:foo'), value:3, xsitype:new WS.QName('int','http://www.w3.org/2000/10/XMLSchema')})

    一旦我為服務(wù)請求構(gòu)建了 SOAP.Envelope,我就會將該 SOAP.Envelope 傳遞到 WS.Call 對象的 invoke 方法,以便調(diào)用該信封內(nèi)編碼的方法: (new WS.Call(service_uri)).invoke(envelope, callback)

    另一種可選方案是手動構(gòu)建 SOAP.Envelope。我會將參數(shù) WS.QName、參數(shù)數(shù)組和編碼樣式傳遞到 WS.Call 對象的 invoke_rpc 方法,如清單 6 所示。


    清單 6. 使用 WS.Call 對象調(diào)用 Web 服務(wù)
    												
    														

    var call = new WS.Call(serviceURI);
    var nsuri = 'urn:foo';
    var qn_op = new WS.QName('method',nsuri);
    var qn_op_resp = new WS.QName('methodResponse',nsuri);
    call.invoke_rpc(
    qn_op,
    new Array(
    {name:'param',value:'bar'}
    ),SOAP.NOENCODING,
    function(call,envelope) {
    // envelope is the response SOAP.Envelope
    // the XML Text of the response is in arguments[2]
    }
    );

    在調(diào)用 invoke 方法或 invoke_rpc 方法時,WS.Call 對象會創(chuàng)建一個基本的 XMLHttpRequest 對象,用包含 SOAP 信封的 XML 元素進(jìn)行傳遞,并接收和解析響應(yīng),然后調(diào)用提供的回調(diào)函數(shù)。

    為了能夠擴展 SOAP 消息的預(yù)處理和后處理,WS.Call 對象允許您注冊一組 WS.Handler 對象,如清單 7 所示。對于調(diào)用周期內(nèi)的每個請求、每個響應(yīng)和每個錯誤,都將調(diào)用這些對象。可以通過擴展 WS.Handler JavaScript 對象來實現(xiàn)新的處理程序。


    清單 7. 創(chuàng)建和注冊響應(yīng)/響應(yīng)處理程序
    												
    														

    var MyHandler = Class.create();
    MyHandler.prototype = (new WS.Handler()).extend({
    on_request : function(envelope) {
    // pre-request processing
    },
    on_response : function(call,envelope) {
    // post-response, pre-callback processing
    },
    on_error : function(call,envelope) {
    }
    });

    var call = new WS.Call(...);
    call.add_handler(new MyHandler());

    處理程序?qū)Σ迦牖蛱崛≌趥鬟f的 SOAP 信封中的信息最有用。例如,您可以設(shè)想一個處理程序自動向 SOAP Envelope 的 Header 插入適當(dāng)?shù)?Web 服務(wù)尋址 (Web Services Addressing) 元素,如清單 8 中的示例所示。


    清單 8. 一個將 Web 服務(wù)尋址操作 Header 添加到請求中的處理程序示例
    												
    														

    var WSAddressingHandler = Class.create();
    WSAddressingHandler.prototype = (new WS.Handler()).extend({
    on_request : function(call,envelope) {
    envelope.create_header().create_child(
    new WS.QName('Action','http://ws-addressing','wsa')
    ).set_value('http://www.example.com');
    }
    });

    WS.Binder 對象(清單 9)執(zhí)行 SOAP.Element 對象的自定義序列化和反序列化。WS.Binder 的實現(xiàn)必須提供以下兩個方法:

    • to_soap_element。將 JavaScript 對象序列化為 SOAP.Element。傳入的第一個參數(shù)是要序列化的值。第二個參數(shù)是 SOAP.Element,必須將要序列化的值序列化為 SOAP.Element。該方法不返回任何值。
    • to_value_object。將 SOAP.Element 反序列化為 JavaScript 對象。該方法必須返回反序列化的值對象。

    清單 9. WS.Binding 實現(xiàn)示例
    												
    														

    var MyBinding = Class.create();
    MyBinding.prototype = (new WS.Binding()).extend({
    to_soap_element : function(value,element) {
    ...
    },
    to_value_object : function(element) {
    ...
    }
    });





    回頁首


    一個簡單示例

    我已經(jīng)提供了一個示例項目來闡釋 Web Services JavaScript Library 的基本功能。該演示所使用的 Web 服務(wù)(如清單 10 所示)已經(jīng)在 WebSphere Application Server 中進(jìn)行了實現(xiàn),并提供了簡單的 Hello World 功能。


    清單 10. 一個簡單的基于 Java 的“Hello World”Web 服務(wù)
    												
    														

    package example;

    public class HelloWorld {
    public String sayHello(String name) {
    return "Hello " + name;
    }
    }

    在實現(xiàn)了該服務(wù)并將其部署到 WebSphere Application Server 后,該服務(wù)(清單 11)的 WSDL 描述定義了您需要傳遞的 SOAP 消息(用于調(diào)用 Hello World 服務(wù))。


    清單 11. HelloWorld.wsdl 的代碼片段
    												
    														

    <wsdl:portType name="HelloWorld">
    <wsdl:operation name="sayHello">
    <wsdl:input
    message="impl:sayHelloRequest"
    name="sayHelloRequest"/>
    <wsdl:output
    message="impl:sayHelloResponse"
    name="sayHelloResponse"/>
    </wsdl:operation>
    </wsdl:portType>

    通過使用 Web Services JavaScript Library,您可以實現(xiàn)一個調(diào)用 Hello World 服務(wù)的方法,如清單 12所示。


    清單 12. 使用 WS.Call 調(diào)用 HelloWorld 服務(wù)
    												
    														

    <html>
    <head>
    ...
    <script
    type="text/javascript"
    src="scripts/prototype.js"></script>
    <script
    type="text/javascript"
    src="scripts/ws.js"></script>
    <script type="text/javascript">
    function sayHello(name, container) {
    var call = new WS.Call('/AjaxWS/services/HelloWorld');
    var nsuri = 'http://example';
    var qn_op = new WS.QName('sayHello',nsuri);
    var qn_op_resp = new WS.QName('sayHelloResponse',nsuri);
    call.invoke_rpc(
    qn_op,
    new Array(
    {name:'name',value:name}
    ),null,
    function(call,envelope) {
    var ret =
    envelope.get_body().get_all_children()[0].
    get_all_children()[0].get_value();
    container.innerHTML = ret;
    $('soap').innerHTML = arguments[2].escapeHTML();
    }
    );

    }
    </script>
    </head>
    ...

    然后,您可以在我們的 Web 應(yīng)用程序中的任意位置通過調(diào)用 sayHello 函數(shù)來調(diào)用 Hello World 服務(wù)。請參見清單 13


    清單 13. 調(diào)用 sayHello 函數(shù)
    												
    														

    <body>
    <input name="name" id="name" />
    <input value="Invoke the Web Service"
    type="button"
    onclick="sayHello($('name').value,$('result'))" />
    <div id="container">Result:
    <div id="result">
    </div>
    <div id="soap">
    </div>
    </div>
    </body>

    調(diào)用成功后的結(jié)果如圖 3 所示。在 Mozilla、Firefox 和 Internet Explorer 中運行該示例應(yīng)該會得到相同的結(jié)果。


    圖 3. Firefox 中的 Hello World 示例
    Firefox 中的 Hello World 示例




    回頁首


    后續(xù)部分

    使 用 Web Services JavaScript Library,可以采用簡單的獨立于瀏覽器的方式將基本的 SOAP Web 服務(wù)合并到 Web 應(yīng)用程序中。在本系列的下一個部分中,您不僅可以探討如何使用該庫來調(diào)用更多基于 Web 服務(wù)資源框架 (WS-Resource Framework ) 系列規(guī)范的高級 Web 服務(wù),而且還可以了解擴展該 Web 服務(wù)功能并將其集成到 Web 應(yīng)用程序中的方法。






    回頁首


    下載

    描述 名字 大小 下載方法
    Sample project ws-wsajaxcode.zip 19 KB ?FTP
    關(guān)于下載方法的信息 Get Adobe? Reader?




    回頁首


    參考資料

    學(xué)習(xí)

    獲得產(chǎn)品和技術(shù)

    討論




    回頁首


    關(guān)于作者

    James M Snell 的照片

    James Snell 是 IBM Emerging Technologies Toolkit 團(tuán)隊的成員。在過去幾年里,他一直致力于新興 Web 服務(wù)技術(shù)和標(biāo)準(zhǔn)的研究,并且還參與了 Atom 1.0 規(guī)范的制定。他現(xiàn)在維護(hù)著一個專注于新興技術(shù)的博客 http://www.ibm.com/developerworks/blogs/dw_blog.jspa?blog=351

    posted on 2006-03-19 16:00 Vincent.Chen 閱讀(317) 評論(0)  編輯  收藏 所屬分類: AJAX

    主站蜘蛛池模板: 亚洲日韩国产一区二区三区在线| 美女被免费视频网站| 好爽…又高潮了毛片免费看| 国产精品亚洲一区二区无码 | 中国在线观看免费高清完整版| 国产精品亚洲专一区二区三区| 亚洲AV无码一区二区三区DV| 一二三四在线播放免费观看中文版视频 | 亚洲第一网站男人都懂| 国产精成人品日日拍夜夜免费| 亚洲男人天堂2018av| 亚洲愉拍99热成人精品热久久| 天天影院成人免费观看| 免费观看亚洲人成网站| 亚洲情a成黄在线观看动漫尤物| 免费无码又爽又刺激聊天APP| 国产成人1024精品免费| 国产亚洲福利在线视频| 亚洲国产精华液网站w| 国产精品二区三区免费播放心| 日本xxxx色视频在线观看免费| 国产偷国产偷亚洲高清在线| 久久精品国产亚洲AV电影| 国产亚洲一区区二区在线| 免费看www视频| 国产免费不卡v片在线观看| 久久久久久av无码免费看大片| 亚洲中文字幕一区精品自拍| 亚洲VA中文字幕无码一二三区| 又爽又高潮的BB视频免费看| 可以免费看黄视频的网站| 免费国产成人午夜在线观看| 免费很黄无遮挡的视频毛片| 亚洲色欲色欲www| 精品亚洲国产成AV人片传媒| 久久久青草青青国产亚洲免观| 性感美女视频在线观看免费精品| 性色午夜视频免费男人的天堂| 好湿好大好紧好爽免费视频| 国产AV无码专区亚洲AV蜜芽| 国产亚洲福利在线视频|