深入淺出dojo/request

來源:互聯網
上載者:User
難度:中等Dojo版本:1.7原作者:Bryan Forbes譯者:Oliver (zhuxw1984@gmail.com)原文連結:http://www.sitepen.com/blog/2012/08/21/introducing-dojorequest/


隨著Dojo向著2.0大步邁進,我們已開始致力於為開發人員提供能在任何JavaScript環境下保持高效生產力的工具。這意味著我們所建立的API必須在所有環境下都保持一致。從這個角度看,有一個領域的API總是被遺漏,那就是Dojo的IO函數。我們已經為開發人員提供了在瀏覽器中發起請求的方法(dojo.xhr*, dojo.io.iframe, dojo.io.script),但有些人不太喜歡這些API所表現出的不一致性(例如dojo.xhrGet以及dojo.io.script.get,等等)。另外,我們還從來沒有提供一套伺服器端的實現;就算提供了,也肯定是另一套不同模組和API,大家就又需要記憶更多東西了。
在Dojo1.8發布之際,我們隆重推出dojo/requestAPI。這套API在所有的瀏覽器、所有要求方法、甚至所有JavaScript環境上都是一致的:

require(["dojo/request"], function(request){    var promise = request(url, options);    promise.then(        function(data){        },        function(error){        }    );    promise.response.then(        function(response){        },        function(error){        }    );    request.get(url, options).then(...);    request.post(url, options).then(...);    request.put(url, options).then(...);    request.del(url, options).then(...);});

dojo/request函數(以及該模組下所有的發起請求的函數)的簽名包含一個URL以及一個選項對象。這個選項對象中可以配置有關這次請求的各種參數。通常情況下使用dojo/request非常簡單,只需要傳遞一個字串,option參數是可省略的。讓我們來看看option對象中的常用配置參數:

  • method:用於本請求的HTTP方法(預設是GET,dojo/request/script會忽略這個參數)
  • query:形如key=value的字串,或者形如{key: 'value'}的對象,包含所有的query參數
  • data:字串或對象(會被dojo/io-query.objectToQuery序列化成字串),表示需要發送的資料(GET和DELET請求會忽略這個參數)
  • handleAs:表示如何處理伺服器端響應的字串,預設"text",其他可能的值包括'json', 'javascript',以及'xml'
  • headers:形如{'Header-Name': 'value'}的對象,包含請求所需要的各種頭部屬性
  • timeout:表示等待多少毫秒算逾時的整數,一旦逾時將取消請求並"拒絕(reject)"所返回的promise。
API的一致性還包括傳回值:所有dojo/request方法都返回一個“保證(promise)”對象,這個promise對象最終會提供響應資料。如果在發起請求時指定了某個響應內容解析器(通過handleAs參數),那麼這個promise對象就會提供這個內容解析器的解析結果,否則它將直接返迴響應的body部分的文本。
dojo/request所返回的promise對象具有一個普通promise沒有的附加屬性:response。這個屬性本身也是一個promise,它將提供一個對象來更詳細地描述這次響應:
  • url:發起請求的最終URL(加上了query字串)
  • options:請求相關的參數
  • text:響應中資料的字串表示
  • data:對響應進行處理後返回的資料(如果handles參數指定了有效解析方式)
  • getHeader(headerName):用於擷取要求標頭部參數的函數;如果某個provider沒有提供頭部資訊,這個函數將返回null。

Provider(提供者,這裡指能夠提供某種請求處理方式的模組 ——譯註)在幕後,dojo/request是通過provider來發起請求的。對於每一個平台dojo都選好了一個合適的預設provider:瀏覽器使用dojo/request/xhr,Node.js使用dojo/request/node。需要指出的是,比較新的瀏覽器(IE9+,FF3.5+,Chrome7+,Safari4+)將使用心得XMLHttpRequest2事件,而不是XMLHttpRequest的onreadystatechange,那隻有在更老的瀏覽器中才會使用。另外,Node.js的provider直接使用了http和https模組,這意味著不用在伺服器端部署任何接受XMLHttpRequest請求的中介層。
如果需要使用一個非預設的provider(例如JSON-P的provider),有如下三種選擇:直接使用非預設provider;把它配置成預設provider;或者配置請求的註冊資訊。
由於所有的provider都遵循dojo/request API,非預設的provider是可以直接使用的。dojo/request的架構設計思想類似於dojo/store。這意味著如果你只有一些JSON-P服務,你可以直接使用dojo/request/script而不用改變基本的API簽名。與其他兩種方式比較起來,這種使用非預設provider的方式靈活性較差,但它是的確是一種完全有效方式。
另一種使用非預設provider的方式是將它配置成預設provider。如果我們知道我們的應用只會使用這一個provider,那這樣做就非常有協助。配置預設provider其實非常簡單,就是把provider的模組ID設定成dojoConfig的requestProvider屬性:
<script>    var dojoConfig = {        requestProvider: "dojo/request/script"    };</script><script src="path/to/dojo/dojo.js"></script>

requestProvider也可以通過data-dojo-config來設定,就像其他配置參數一樣。另外,因為任何遵循dojo/request API的函數都能作為預設provider,我們當然也可以開發一個自訂的模組,將dojo/request/xhr封裝起來,再加上額外的頭部資訊(例如用於身分識別驗證),這樣就能作為一個自訂的provider來給我們的應用使用了。而且,在測試階段,我們也可以使用一個特殊的provider來類比伺服器發回的響應,這樣就能驗證我們的應用是否在發出正確的請求。
雖然比起直接使用非預設provider來,將其配置成預設能為我們提供更大的靈活性,但這麼做仍然不能只通過一個API(dojo/request)就做到根據預設條件來自動使用不同provider的能力。假設我們的應用有一些資料服務,其中一個服務需要一組用於身分識別驗證的頭部資訊,而另一個需要完全不同的另一組頭部資訊。或者一個需要JSON-P而另一個需要XMLHttpRequest。這種情況下就是dojo/request/registry閃亮登場的時候了。
註冊機制Dojox中有一個存在了很久但並沒有得到廣泛使用的模組dojox/io/xhrPlugins。這個模組可以讓dojo.xhr*成為所有請求的介面,無論這些請求是通過JSONP發送還是iframe,甚至是其他使用者自訂的方式。這個統一介面的思想非常有用,因此被沿用到dojo/request/registry中。
dojo/request/registry同樣遵循dojo/request API(因此它本身就可以作為一個provider),不過增加了一個register函數:

// 如果一個請求的URL是"some/url",provider就會被用來處理這個請求registry.register("some/url", provider); // 如果一個請求的URL以"some/url"開始,provider就會被用來處理這個請求registry.register(/^some\/url/, provider); // 如果一個請求是一HTTP GET方法發送的,provider就會被用來處理這個請求registry.register(    function(url, options){        return options.method === "GET";    },    provider); // 如果不能匹配到任何登入的條件,預設provider將被使用
如果所有條件都不滿足,而且也沒有備用provider可用,那麼當前環境的預設provider將被啟用。由於dojo/request/registry符合dojo/request API,它可以作為預設provider:
<script>    var dojoConfig = {        requestProvider: "dojo/request/registry"    };</script><script src="path/to/dojo/dojo.js"></script><script>    require(["dojo/request", "dojo/request/script"],        function(request, script){            request.register(/^\/jsonp\//, script);            ...        }    );</script>
如果我們想要使用平台預設的provider(對於瀏覽器來說是XHR)作為備用,那這樣做當然很好,但我們也可以通過上例中的最後一條語句設定自己的備用provider,只是在這句話之後就不能再註冊其他provider了。設定在requestProvider參數上的dojo/request/registry還可以接受外掛程式作為備用provider:
<script>    var dojoConfig = {        requestProvider: "dojo/request/registry!my/authProvider"    };</script><script src="path/to/dojo/dojo.js"></script><script>    require(["dojo/request", "dojo/request/script"],        function(request, script){            request.register(/^\/jsonp\//, script);            ...        }    );</script>
好了,現在任何不滿足預設條件的請求都會由my/authProvider來處理。
註冊provide功能的強大可能還不是那麼明顯。現在讓我們來看幾個讓註冊功能大顯身手的情境。首先,考慮一個應用,它的伺服器端API是在不斷變化的。也就是說雖然我們知道每一個具體的終端服務,但我們不知道會需要什麼樣的頭部資訊,甚至也不知道響應中會返回什麼樣的JSON對象。我們可以很容易地為每一項服務註冊一個臨時provider,然後立馬開始開發使用者介面。假設我們猜想/service1將在items屬性中返回JSON格式的資料項目,而/service2將在data屬性中返回這些資料項目:
request.register(/^\/service1\//, function(url, options){    var promise = xhr(url, lang.delegate(options, { handleAs: "json" })),         dataPromise = promise.then(function(data){            return data.items;        });    return lang.delegate(dataPromise, {        response: promise.response    });});request.register(/^\/service2\//, function(url, options){    var promise = xhr(url, lang.delegate(options, { handleAs: "json" })),         dataPromise = promise.then(function(data){            return data.data;        });    return lang.delegate(dataPromise, {        response: promise.response    });});
現在所有在使用者介面中用到的服務要求都可以通過request(url, options).then(...)的形式來使用,並且它們都會接收到正確的資料。隨著開發過程的進行,某個服務端團隊可能決定改讓/service1在data屬性中以JSON格式返回資料項目,而/service2則以XML的格式返回。如果不使用註冊機制,這將導致大量的代碼改動。有了註冊機制,我們已經將我們的widget和store所需要的介面和服務所能提供的介面解耦了,這意味著伺服器端團隊的決定只會導致兩處代碼改變:在我們的兩個provider中。理論上,我們甚至能將使用者介面與URL進行進一步解耦,通過使用通用的URL讓我們的註冊機制自動將正確的服務終端映射到正確的provider上。這就避免了服務終端的改動導致的前端代碼的大量修改。
這種解耦也可以拓展到測試上。通常在單元測試中無法獲得遠程服務:遠端資料可能變化,遠程伺服器也可能不可用。這也是為什麼推薦使用待用資料做測試。但如果我們的widget和使用者介面把服務終端和對應請求都寫死在裡面了,我們還怎麼去測試呢?而如果我們使用了dojo/request/registry,只需要註冊一個專門為測試工作返回待用資料的provider就行了,所有的API調用都不需要修改,現有應用中不需要重寫任何代碼。
結論可見,dojo/request是為開發人員編寫的:對於簡單的情境有簡單的API,對於複雜情境也有非常靈活的選項。
相關資料更多關於dojo/request的學習資料請參考:
  • Ajax with dojo/request tutorial
  • dojo/request reference guide
  • dojo/request API

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.