zoukankan      html  css  js  c++  java
  • 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. }

    上面基本根据当前案例进行代码解析,很多情况没有一一列出,感兴趣的童鞋可以通过打断点调试的方式来解析代码。





  • 相关阅读:
    重构构建的平凡之路
    andriod CheckBox
    andriod 用户名和密码
    andriod ==和equals
    android布局--Android fill_parent、wrap_content和match_parent的区别
    Android 五大布局
    一个帖子学会Android开发四大组件
    Error retrieving parent for item: No resource found that matches the given name 'android:TextAppearance.Material.Widget.Button.Inverse'.
    andriod VideoView
    arcgis andriod 长按获得当前信息
  • 原文地址:https://www.cnblogs.com/rubyisaPM/p/4412897.html
Copyright © 2011-2022 走看看