jquery的http請求對響應內容的處理


寫在前面:在學習XMLHttpRequest對象時碰到的一個問題,發現jquery的http請求會自動處理響應內容,變為開發者想要的數據,下面來看看吧:

實驗案例:

 
 
 
         
  1. var xhr=new XMLHttpRequest();
  2. xhr.onreadystatechange=function(e){
  3. console.log(e);
  4. if(xhr.readyState==4 && xhr.status==200){
  5. console.log(xhr);
  6. console.log(xhr.responseText);
  7. }
  8. }
  9. xhr.open('get','./data.json');
  10. xhr.send();

請求成功后的xhr:

response中已經有了數據,響應內容默認為字符串
responseType為'',也就是默認值
responseText中是響應主體的內容
responseURL指出了我們請求的資源路徑

為什么返回的不是json對象?

上圖中的信息:responseType是一個空字符串,也就是指明了返回的是一個字符串,而且從下面的log我們也可以看出來,為了清楚,我把xhr.responseText的類型也打印了出來,確實是string。
而如果我們換成下面的代碼:

 
 
 
         
  1. var xhr=$.ajax({
  2. url:'./data.json',
  3. success:function(data){
  4. console.log(data);
  5. }
  6. });
  7. console.log(xhr);

得到結果截圖如下:

這個被jQuery改的面目全非的xmlhttprequest對象,先看一個左側的屬性,其中有一個responseJSON,這是jquery的實現,標准中是沒有這個屬性的,而它的responseText是字符串。所以success回調應該就是調的這個屬性咯。看下請求,沒有什么區別:Content-Type都是application/json ,其實我們再切到response標簽看下,是一樣的數據格式。所以是不是可以說原生獲取json格式數據的話,值都是json字符串形式的值?

這里的jquery版本為1.11.2,查看源碼可以發現:在ajax方法中定義的done方法內,有這么一句:

 
 
 
         
  1. // Get response data 這里是得到相應的內容,本例就是"'{"username":"ruby","age":"18"}'"
  2. if ( responses ) {
  3. response = ajaxHandleResponses( s, jqXHR, responses );
  4. }
  5. // Convert no matter what (that way responseXXX fields are always set)
  6. response = ajaxConvert( s, response, jqXHR, isSuccess );

也就是說,在得到最終請求數據時,jquery會去做響應內容的自動轉換,先來看ajaxHandleResponses方法,它用於返回響應內容:

 
 
 
         
  1. function ajaxHandleResponses(s, jqXHR, responses) {
  2. var firstDataType, ct, finalDataType, type,
  3. contents = s.contents,
  4. dataTypes = s.dataTypes;
  5. // Remove auto dataType and get content-type in the process
  6. while (dataTypes[0] === "*") {
  7. dataTypes.shift();
  8. if (ct === undefined) {
  9. ct = s.mimeType || jqXHR.getResponseHeader("Content-Type");
  10. /*這里的s是使用ajax傳入的參數轉化而來的對象,用於存儲前端開發人員發起該請求時對請求的一些設置和js默認對請求的設置,s.mimeType是使用overrideMIMEType時會被寫入s的,其實也就是在ajax方法中我們指定的contentType,如果沒有該屬性,就是查找相應對象的Content-Type屬性,而這個是肯定有值的,本例中ct='application/json',即獲取到了響應報文中報頭Content-Type的值*/
  11. }
  12. }
  13. // Check if we're dealing with a known content-type
  14. if (ct) {
  15. for (type in contents) {
  16. /*
  17. contents是一個固定的對象,用於匹配各種類型的數據
  18. {
  19. html: /html/
  20. json: /json/
  21. script: /(?:java|ecma)script/
  22. xml: /xml/
  23. }
  24. */
  25. if (contents[type] && contents[type].test(ct)) {
  26. dataTypes.unshift(type);
  27. /*
  28. 這里我們顯然是匹配到了json這一項,所以dataTypes中加上一項['json']
  29. */
  30. break;
  31. }
  32. }
  33. }
  34. // Check to see if we have a response for the expected dataType
  35. if (dataTypes[0] in responses) {
  36. finalDataType = dataTypes[0];
  37. /*
  38. 如果這個類型的數據在responses中正好有,那么就直接將最終類型定義為dataType中的這一項,本例中,dataTypes[0]為'json',但實際返回的響應是text。responses就是根據相應內容生成的響應對象,這里是"{text:"{"username":"ruby","age":"18"}"}".
  39. */
  40. } else {
  41. // Try convertible dataTypes
  42. for (type in responses) {
  43. if (!dataTypes[0] || s.converters[type + " " + dataTypes[0]]) {
  44. /*
  45. 檢測responses中的各個類型的值是否可以轉換為我們想得到的類型, 本例中這里的type為'text',s.converters定義的是各種轉換用到的函數,比如s.converters['text json']=JSON.parse。本例中這里是可以轉換的。列出來吧:
  46. s.converters:{
  47. "text script": function( text ) {
  48. jQuery.globalEval( text );
  49. return text;
  50. },
  51. // Convert anything to text
  52. "* text": String,
  53. // Text to html (true = no transformation)
  54. "text html": true,
  55. // Evaluate text as a json expression
  56. "text json": jQuery.parseJSON,
  57. // Parse text as xml
  58. "text xml": jQuery.parseXML
  59. }
  60. */
  61. finalDataType = type;
  62. break;
  63. }
  64. if (!firstDataType) {
  65. firstDataType = type;
  66. }
  67. }
  68. // Or just use first one
  69. finalDataType = finalDataType || firstDataType;
  70. }
  71. // If we found a dataType
  72. // We add the dataType to the list if needed
  73. // and return the corresponding response
  74. if (finalDataType) {
  75. if (finalDataType !== dataTypes[0]) {
  76. dataTypes.unshift(finalDataType);
  77. //完善s.dataTypes中的值,即完善響應數據的類型,此時為['text','json']
  78. }
  79. return responses[finalDataType];
  80. //最終返回responses['text']
  81. }
  82. }

再來看ajaxConvert方法:

 
 
 
         
  1. /* Chain conversions given the request and the original response
  2. * Also sets the responseXXX fields on the jqXHR instance
  3. */
  4. function ajaxConvert(s, response, jqXHR, isSuccess) {
  5. var conv2, current, conv, tmp, prev,
  6. converters = {},
  7. // Work with a copy of dataTypes in case we need to modify it for conversion
  8. dataTypes = s.dataTypes.slice();
  9. //數組copy這么寫?不知道為啥~你知道的話還望不吝賜教~
  10. // Create converters map with lowercased keys
  11. if (dataTypes[1]) {
  12. for (conv in s.converters) {
  13. converters[conv.toLowerCase()] = s.converters[conv];
  14. //構造一個轉換對象,內容是s.converters中的那些轉換函數.
  15. }
  16. }
  17. current = dataTypes.shift();
  18. // Convert to each sequential dataType
  19. while (current) {
  20. if (s.responseFields[current]) {
  21. jqXHR[s.responseFields[current]] = response;
  22. /*
  23. 這里給jqXHR即jquery構造出來的XMLHttpRequest對象賦值,在本例中,它在此添加了兩個屬性,一個是responseText,一個是responseJson
  24. */
  25. }
  26. // Apply the dataFilter if provided
  27. if (!prev && isSuccess && s.dataFilter) {
  28. response = s.dataFilter(response, s.dataType);
  29. }
  30. prev = current;
  31. current = dataTypes.shift();
  32. //記住第一個類型,再獲取第二個類型,這里的prev為‘text’, current為'json'。
  33. if (current) {
  34. // There's only work to do if current dataType is non-auto
  35. if (current === "*") {
  36. current = prev;
  37. // Convert response if prev dataType is non-auto and differs from current
  38. } else if (prev !== "*" && prev !== current) {
  39. // Seek a direct converter
  40. conv = converters[prev + " " + current] || converters["* " + current];
  41. //看看是否有prev類轉current類的轉換方法
  42. // If none found, seek a pair
  43. if (!conv) {
  44. for (conv2 in converters) {
  45. // If conv2 outputs current
  46. tmp = conv2.split(" ");
  47. if (tmp[1] === current) {
  48. // If prev can be converted to accepted input
  49. conv = converters[prev + " " + tmp[0]] ||
  50. converters["* " + tmp[0]];
  51. if (conv) {
  52. // Condense equivalence converters
  53. if (conv === true) {
  54. conv = converters[conv2];
  55. // Otherwise, insert the intermediate dataType
  56. } else if (converters[conv2] !== true) {
  57. current = tmp[0];
  58. dataTypes.unshift(tmp[1]);
  59. }
  60. break;
  61. }
  62. }
  63. }
  64. }
  65. // Apply converter (if not an equivalence)
  66. if (conv !== true) {
  67. // Unless errors are allowed to bubble, catch and return them
  68. if (conv && s["throws"]) {
  69. response = conv(response);
  70. } else {
  71. try {
  72. response = conv(response);
  73. //轉換為我們想要的數據類型,截至此我們已經得到想要的json數據啦
  74. } catch (e) {
  75. return {
  76. state: "parsererror",
  77. error: conv ? e : "No conversion from " + prev + " to " + current
  78. };
  79. }
  80. }
  81. }
  82. }
  83. }
  84. }
  85. return {state: "success", data: response};
  86. }

上面基本根據當前案例進行代碼解析,很多情況沒有一一列出,感興趣的童鞋可以通過打斷點調試的方式來解析代碼。






免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM