jQuery源码分析系列(34) : Ajax - 预处理jsonp

上一章大概讲了前置过滤器和请求分发器的做用,这一章主要是具体分析每种对应的处理方式javascript

$.ajax()调用不一样类型的响应,被传递到成功处理函数以前,会通过不一样种类的预处理(prefilters)。 预处理的类型取决于由更加接近默认的Content-Type响应,但能够明确使用dataType选项进行设置。若是提供了dataType选项, 响应的Content-Type头信息将被忽略。css

有效的数据类型是text, html, xml, json,jsonp,和 script.html

dataType:预期服务器返回的数据类型。若是不指定,jQuery 将自动根据 HTTP 包 MIME 信息来智能判断,好比XML MIME类型就被识别为XML。在1.4中,JSON就会生成一个JavaScript对象,而script则会执行这个脚本。随后服务器端返回的数据会根据这个值解析后,传递给回调函数。可用值:java

 


script 类型jquery

$.ajax({
    type     : "GET",
    url      : "test.js",
    dataType : "script",
    complete: function(jqXHR, status) {
        console.log(jqXHR, status)
    }
});

根据API的说明可知,若是dataType类型为script的时候,须要处理ajax

1 执行脚本json

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属性方法来调用,不是传递的一个回调句柄

 

篇幅比较长了了 下章再合并讲解内部实现及请求分发器

相关文章
相关标签/搜索