標籤:style class blog code java http
上一章大概講了前置過濾器和請求分發器的作用,這一章主要是具體分析每種對應的處理方式
$.ajax()調用不同類型的響應,被傳遞到成功處理函數之前,會經過不同種類的預先處理(prefilters)。 預先處理的類型取決於由更加接近預設的Content-Type響應,但可以明確使用dataType選項進行設定。如果提供了dataType選項, 響應的Content-Type頭資訊將被忽略。
有效資料類型是text, html, xml, json,jsonp,和 script.
dataType:預期伺服器返回的資料類型。如果不指定,jQuery 將自動根據 HTTP 包 MIME 資訊來智能判斷,比如XML MIME類型就被識別為XML。在1.4中,JSON就會產生一個JavaScript對象,而script則會執行這個指令碼。隨後伺服器端返回的資料會根據這個值解析後,傳遞給回呼函數。可用值:
script 類型
$.ajax({ type : "GET", url : "test.js", dataType : "script", complete: function(jqXHR, status) { console.log(jqXHR, status) }});
根據API的說明可知,如果dataType類型為script的時候,需要處理
1 執行指令碼
2 內容當作純文字返回
3 預設情況下不會通過在URL中附加查詢字串變數 "_=[TIMESTAMP]" 進行自動緩衝結果,除非設定了cache參數為true
4 在遠程請求時(不在同一個域下),所有POST請求都將轉為GET請求。(因為將使用DOM的script標籤來載入)
針對上述四點,我們看看處理的流程
inspectPrefiltersOrTransports(prefilters, s, options, jqXHR);
此時的dataType類型就會經過對應的預先處理ajaxPrefilter("script")
cache (預設: true, dataType為"script"和"jsonp"時預設為false)
jQuery.ajaxPrefilter("script", function(s) { if (s.cache === undefined) { s.cache = false; } if (s.crossDomain) { s.type = "GET"; }});
預先處理的處理就是將其緩衝為設定為 false ,瀏覽器將不緩衝此頁面
這將在請求的URL的查詢字串中追加一個時間戳記參數,以確保每次瀏覽器下載的指令碼被重新請求
工作原理是在GET請求參數中附加"_={timestamp}"在請求的地址後面加一個時間戳記
if (s.cache === false) { s.url = rts.test(cacheURL) ? // If there is already a ‘_‘ parameter, set its value cacheURL.replace(rts, "$1_=" + ajax_nonce++) : // Otherwise add one to the end cacheURL + (ajax_rquery.test(cacheURL) ? "&" : "?") + "_=" + ajax_nonce++;}
此時的 s.url = "test.js?_=1402362401890";
該參數不是其他請求所必須的,除了在IE8中,當一個POST請求一個已經用GET請求過的URL
json jsonp 類型
- "json": 把響應的結果當作 JSON 執行,並返回一個JavaScript對象。在 jQuery 1.4 中,JSON 格式的資料以嚴格的方式解析,如果格式有錯誤,jQuery都會被拒絕並拋出一個解析錯誤的異常。(見json.org的更多資訊,正確的JSON格式。)
- 如果指定的是
json,響應結果作為一個對象,在傳遞給成功處理函數之前使用jQuery.parseJSON進行解析。 解析後的JSON對象可以通過該jqXHR對象的responseJSON屬性獲得的。
- json的處理只要是在ajaxConvert方法中把結果給轉換成需要是json格式,這是後面的內容,這裡主要研究下jsonp的預先處理
關於JSONP傳送飛機:http://baike.baidu.com/view/2131174.htm
JSONP是一個非官方的協議,它允許在伺服器端整合Script tags返回至用戶端,通過javascript callback的形式實現跨域訪問(這僅僅是JSONP簡單的實現形式)。JSON系統開發方法是一種典型的面向資料結構的分析和設計方法,以活動為中心,一連串的活動的順序組合成一個完整的背景工作處理序。
跨域這個問題的產生根本原因是瀏覽器的同源策略限制,理解同源策略的限制同源策略是指阻止代碼獲得或者更改從另一個網域名稱下獲得的檔案或者資訊。也就是說我們的請求地址必須和當前網站的地指相同。同源策略通過隔離來實現對資源的保護。這個策略的曆史非常悠久從Netscape Navigator 2.0時代就開始了。
- 解決這個限制的一個相對簡單的辦法就是在伺服器端發送請求,伺服器充當一個到達第三方資源的代理中繼。雖然是用廣泛但是這個方法卻不夠靈活。
- 另一個辦法就是使用架構(frames),將第三方網站的資源套件含進來,但是包含進來的資源同樣要受到同源策略的限制。
- 有一個很巧妙的辦法就是在頁面中使用動態代碼元素,代碼的源指向服務地址並在自己的代碼中載入資料。當這些代碼載入執行的時候,同源策略就不會起到限制。但是如果代碼試圖下載檔案的時候執行還是會失敗,幸運的是,我們可以使用JSON(JavaScript Object Notation)來改進這個應用
JSON和JSONP
與XML相比,JSON是一個輕量級的資料交換格式。JSON對於JavaScript開發人員充滿魅力的原因在於JSON本身就是Javascript中的對象。
例如一個ticker對象
var ticker = {symbol:‘IBM‘,price:100}
而JSON串就是 {symbol:‘IBM‘,price:100}
這樣我們就可以在函數的參數中傳遞JSON資料。我們很容易掌握在函數中使用動態JSON參數資料,但是我們的目的並不是這個。
通過使我們的函數能夠載入動態JSON資料,我們就能夠處理動態資料,這項技術叫做 Dynamic Javascript Insertion。
index.html 中
function showPrice(data){ alert("Symbol:" + data.symbol + ", Price:" + data.price); }
然後動態載入ticker.js指令碼
var data = {symbol:‘IBM‘, price:100}; showPrice(data);
代碼通過動態加入Javascript代碼,來執行函數載入資料
正如之前提到過的,同源策略對於動態插入的代碼不適用。也就是你可以從不同的域中載入代碼,來執行在他們代碼中的JSON資料。
這就是JSONP(JSON with Padding)。注意,使用這種方法時,你必須在頁面中定義回呼函數,就像上例中的showPrice一樣。
我們通常所說的JSONP服務(遠程JSON服務),實際上就是一種擴充的支援在使用者定義函數中包含返回資料的能力。這種方法依賴於必須接受一個回呼函數的名字作為參數。
然後執行這個函數,處理JSON資料,並顯示在客戶頁面上。
JSONP的用戶端具體實現:
<!DOCTYPE html><html><head> <meta charset="utf-8"> <script type="text/javascript"src="http://code.jquery.com/jquery-1.11.1.min.js"></script> <script> alert(jQuery) </script></head><body></body></html>
通過script是src載入遠端jQuery毫無疑問是可以正常啟動並執行,所以不難發現Web頁面上調用js檔案時則不受是否跨域的影響
當然不僅如此,我們還發現凡是擁有"src"這個屬性的標籤都擁有跨域的能力,比如<script>、<img>、<iframe>等
在進一步我們換成契約式介面
<!DOCTYPE html><html><head> <meta charset="utf-8"> <script type="text/javascript"src="http://code.jquery.com/jquery-1.11.1.min.js"></script> <script type="text/javascript"> function remoteLoad(data){ alert(data) //遠端資料 } </script></head><body></body></html>http://code.jquery.com/jquery-1.11.1.min.js 檔案中執行remoteLoad(‘載入的資料‘)
顯而易見OK了,通過載入遠端指令碼到本地中執行,很好的繞開了跨域的問題了,但是這樣的請求是有問題的,介面是契約式的?
怎麼讓遠程js知道它應該調用的本地函數叫什麼名字呢?畢竟是jsonp的服務者都要面對很多服務物件,而這些服務物件各自的本地函數都不相同啊?我們接著往下看。
更進一步增加動態回調
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head> <title></title> <script type="text/javascript"> var remoteLoad= function(data){}; var url = "http://code.jquery.com/jquery-1.11.1.min.js?code=1111&callback=remoteLoad"; var script = document.createElement(‘script‘); script.setAttribute(‘src‘, url); document.getElementsByTagName(‘head‘)[0].appendChild(script); </script></head><body></body>
不再直接把遠程js檔案寫死,而是編碼實現動態查詢,而這也正是jsonp用戶端實現的核心部分,本例中的重點也就在於如何完成jsonp調用的全過程。
我們看到調用的url中傳遞了一個callback參數則告訴伺服器,我的本地回呼函數叫做remoteLoad,所以請把查詢結果傳入這個函數中進行調用。
所以總結其實json的一個核心點:允許使用者傳遞一個callback參數給服務端,然後服務端返回資料時會將這個callback參數作為函數名來包裹住JSON資料,這樣用戶端就可以隨意定製自己的函數來自動處理返回資料了。
基本原理OK了,我們看看jQuery的實現,其實也大同小異
$.ajax({ url : "remoteLoad.js", dataType : "jsonp", jsonp : "callback", //傳遞給請求處理常式或頁面的,用以獲得jsonp回呼函數名的參數名(一般預設為:callback) jsonpCallback : "Handler", //自訂的jsonp回呼函數名稱,預設為jQuery自動產生的隨機函數名,也可以寫"?",jQuery會自動為你處理資料 success: function(data) { console.log(arguments) }});
jQuery的區別最大的不同的就自動幫你產生回呼函數並把資料取出來供success屬性方法來調用,不是傳遞的一個回調控制代碼
篇幅比較長了了 下章再合并講解內部實現及請求分發器
如果您覺得這文章對您有協助,請點擊【推薦一下】,想跟我一起進步嗎?那就【關注】我吧!