json jsonp 类型

  "json":  把响应的结果当作 JSON 执行,并返回一个JavaScript对象。如果指定的是json,响应结果作为一个对象,在传递给成功处理函数之前使用jQuery.parseJSON进行解析。 解析后的JSON对象可以通过该jqXHR对象的responseJSON属性获得的。json的处理只要是在ajaxConvert方法中把结果给转换成需要是json格式,这是后面的内容,这里主要研究下jsonp的预处理。

  "jsonp": JSONP是一个非官方的协议,它允许在服务器端集成Script tags返回至客户端,通过javascript callback的形式实现跨域访问(这仅仅是JSONP简单的实现形式)。

  跨域这个问题的产生根本原因是浏览器的同源策略限制,理解同源策略的限制同源策略是指阻止代码获得或者更改从另一个域名下获得的文件或者信息。也就是说我们的请求地址必须和当前网站的地指相同。同源策略通过隔离来实现对资源的保护。这个策略的历史非常悠久从Netscape Navigator 2.0时代就开始了。

  解决这个限制的一个相对简单的办法就是在服务器端发送请求,服务器充当一个到达第三方资源的代理中继。虽然是用广泛但是这个方法却不够灵活。

  另一个办法就是使用框架(frames),将第三方站点的资源包含进来,但是包含进来的资源同样要受到同源策略的限制。

  有一个很巧妙的办法就是在页面中使用动态代码元素,代码的源指向服务地址并在自己的代码中加载数据。当这些代码加载执行的时候,同源策略就不会起到限制。但是如果代码试图下载文件的时候执行还是会失败,幸运的是,我们可以使用JSON(JavaScript Object Notation)来改进这个应用

  

a. JSONP的客户端具体实现


  先看一个简单的例子

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script 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 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 文件中执行(在文档ready之后)
remoteLoad('加载的数据')

  显而易见是可行的,通过加载远程的脚本到本地中执行,很好的绕开了跨域的问题了,但是这样的请求是有问题的,接口是契约式的?

  怎么让远程js知道它应该调用的本地函数叫什么名字呢?毕竟是jsonp的服务者都要面对很多服务对象,而这些服务对象各自的本地函数都不相同啊?我们接着往下看。

  更进一步增加动态回调

<!DOCTYPE html>
<html>
<head>
  <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>
</html>

  不再直接把远程js文件写死,而是编码实现动态查询,而这也正是jsonp客户端实现的核心部分,我们看到调用的url中传递了一个callback参数则告诉服务器,我的本地回调函数叫做remoteLoad,所以请把查询结果传入这个函数中进行调用。

b. jQuery的处理


  在jQuery的ajax中jsonp和jsonpCallback分别对应指定“callback”和“remoteLoad”这两个值。

  jsonp的默认值为“callback”,jsonpCallback的默认值是一个时间戳字段(jQuery.expando + "_" + ( ajax_nonce++ ))比如“jQuery19107833043907303363_1444871956399”。

  我们也可以指定他们,比如{jsonp:”chuaCallBack”,jsonpCallBack:”chuaRemote”}那么在传递的时候url就变成了"http://code.jquery.com/jquery-1.11.1.min.js?..&chuaCallBack=chuaRemote"。

  所以总结其实json的一个核心点:允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了。

$.ajax({
url : "remoteLoad.js",
dataType : "jsonp",
jsonp : "callback", //传递给请求处理程序或页面的,用以获得jsonp回调函数名的参数名(一般默认为:callback)
jsonpCallback : "Handler", //自定义的jsonp回调函数名称,默认为jQuery自动生成的随机函数名,也可以写"?",jQuery会自动为你处理数据
success: function(data) {
console.log(arguments)
}
});

  基本原理OK了,我们看看上面jQuery的使用没有什么太大的区别。

  jQuery其实也大同小异,jQuery的区别最大的不同的就自动帮你生成回调函数并把数据取出来供success属性方法来调用,不是传递的一个回调句柄。

  jQuery实现jsonp的源码处理步骤如下。

  首先,我们需要设置回调函数名称,可以自己定义也可以让jQuery自动设置。

//获取回调函数名称(这个名称可以在ajax的jsonpCallback选项上设置,
//否则通过jQuery默认的方式jsonpCallback()来设置)
//这个回调函数名称是用来告诉后台需要将返回数据包裹到该函数中,返回前端后执行
callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ?
s.jsonpCallback() :
s.jsonpCallback;

  然后,将回调插入到url或者data选项中(一般来说是URL

if ( jsonProp ) {
s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName );
} else if ( s.jsonp !== false ) {
s.url += ( ajax_rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName;
}

  再然后,安装回调

//安装回调
overwritten = window[ callbackName ];
window[ callbackName ] = function() {
responseContainer = arguments;
};

  很明显,本来后台应该执行overwritten这个回调的,但是现在换成了执行后面重写的这个回调,那么在jsonp请求完成后就会执行这个重写方法,给responseContainer赋值了。别急overwritten后面有调用到。

  最后,添加延时对象的always响应执行overwritten。

//清除函数(转换完成后执行)
jqXHR.always(function() {
//保存先前存的值
window[ callbackName ] = overwritten; //将jsonpCallback设置回原始值
if ( s[ callbackName ] ) {
//确保重新使用jsonpCallback选项没有杂质
s.jsonpCallback = originalSettings.jsonpCallback; //将callbackName压入oldCallbacks以备将来使用
oldCallbacks.push( callbackName );
} //在请求响应后,如果jsonpCallback指定的回调是一个函数则调用它
if ( responseContainer && jQuery.isFunction( overwritten ) ) {
overwritten( responseContainer[ 0 ] );
} responseContainer = overwritten = undefined;
});

  所以overwritten是在这里面执行的,前面源码中重载过的那个回调在后台调用后获取到了responseContainer值也被用到了。可见我们在设置的jsonpCallback选项指定的回调名(例如chuaRemote)对应的回调先被保存到overwritten中,而这个原始的chuaRemote被赋值为function() {  responseContainer = arguments;};

  在响应处理中chuaRemote会被调用让responseContainer获取到响应值。最后会执行到jqXHR.always添加的函数处理。将chuaRemote恢复到原来的函数overwritten,并执行overwritten(jsonpCallback指定的回调)。主要是always这个监听处理中还清除callbackName指定的函数,以及添加回到历史等等处理。

  

  好了jsonp就分析到这里了,欢迎拍砖。

  如果觉得本文不错,请点击右下方【推荐】!

jQuery-1.9.1源码分析系列(十六)ajax——jsonp原理的更多相关文章

  1. Spring Ioc源码分析系列--@Autowired注解的实现原理

    Spring Ioc源码分析系列--@Autowired注解的实现原理 前言 前面系列文章分析了一把Spring Ioc的源码,是不是云里雾里,感觉并没有跟实际开发搭上半毛钱关系?看了一遍下来,对我的 ...

  2. ABP源码分析二十六:核心框架中的一些其他功能

    本文是ABP核心项目源码分析的最后一篇,介绍一些前面遗漏的功能 AbpSession AbpSession: 目前这个和CLR的Session没有什么直接的联系.当然可以自定义的去实现IAbpSess ...

  3. ABP源码分析三十六:ABP.Web.Api

    这里的内容和ABP 动态webapi没有关系.除了动态webapi,ABP必然是支持使用传统的webApi.ABP.Web.Api模块中实现了一些同意的基础功能,以方便我们创建和使用asp.net w ...

  4. ABP源码分析四十六:ABP ZERO中的Ldap模块

    通过AD作为用户认证的数据源.整个管理用户认证逻辑就在LdapAuthenticationSource类中实现. LdapSettingProvider:定义LDAP的setting和提供Defaut ...

  5. Android源码分析(十六)----adb shell 命令进行OTA升级

    一: 进入shell命令界面 adb shell 二:创建目录/cache/recovery mkdir /cache/recovery 如果系统中已有此目录,则会提示已存在. 三: 修改文件夹权限 ...

  6. spark 源码分析之十六 -- Spark内存存储剖析

    上篇spark 源码分析之十五 -- Spark内存管理剖析 讲解了Spark的内存管理机制,主要是MemoryManager的内容.跟Spark的内存管理机制最密切相关的就是内存存储,本篇文章主要介 ...

  7. jQuery-1.9.1源码分析系列(六) 延时对象应用——jQuery.ready

    还记不记得jQuery初始化函数jQuery.fn.init中有这样是一个分支 //document ready简便写法$(function(){…}) } else if ( jQuery.isFu ...

  8. Vue.js 源码分析(二十六) 高级应用 作用域插槽 详解

    普通的插槽里面的数据是在父组件里定义的,而作用域插槽里的数据是在子组件定义的. 有时候作用域插槽很有用,比如使用Element-ui表格自定义模板时就用到了作用域插槽,Element-ui定义了每个单 ...

  9. jQuery-1.9.1源码分析系列(六) 延时对象续——辅助函数jQuery.when

    $.when的说明 描述: 提供一种方法来执行一个或多个对象的回调函数,返回这些对象的延时(Deferred)对象. 说明(结合实例和源码): 如果你不传递任何参数,  jQuery.when()将返 ...

  10. jQuery-1.9.1源码分析系列(六) 延时对象

    首先我们需要明白延时对象有什么用? 第一个作用,解决时序以及动态添加执行函数的问题. function a(){alert(1)}; function b(){alert(2)}; function ...

随机推荐

  1. Dapper where Id in的解决方案

    简单记一下,一会出去有点事情~ 我们一般写sql都是==>update NoteInfo set NDataStatus=@NDataStatus where NId in (@NIds) Da ...

  2. ExtJS 4.2 业务开发(三)数据添加和修改

    接上面的船舶管理业务,这里介绍添加和修改操作. 目录 1. 添加操作 2. 修改操作 3. 在线演示 1. 添加操作 1.1 创建AddShipWindow.js 在业务中的view目录下创建一个Ad ...

  3. C#多线程之线程池篇2

    在上一篇C#多线程之线程池篇1中,我们主要学习了如何在线程池中调用委托以及如何在线程池中执行异步操作,在这篇中,我们将学习线程池和并行度.实现取消选项的相关知识. 三.线程池和并行度 在这一小节中,我 ...

  4. jQuery.template.js 简单使用

    之前看了一篇文章<我们为什么要尝试前后端分离>,深有同感,并有了下面的评论: 我最近也和前端同事在讨论这个问题,比如有时候前端写好页面给后端了,然后后端把这些页面拆分成很多的 views, ...

  5. Java compiler level does not match解决方法

    从别的地方导入一个项目的时候,经常会遇到eclipse/Myeclipse报Description  Resource Path Location Type Java compiler level d ...

  6. 深入理解javascript函数定义与函数作用域

    最近在学习javascript的函数,函数是javascript的一等对象,想要学好javascript,就必须深刻理解函数.本人把思路整理成文章,一是为了加深自己函数的理解,二是给读者提供学习的途径 ...

  7. Android Bitmap 和 ByteArray的互相转换

    Android Bitmap 和 ByteArray的互相转换 移动平台图像处理,需要将图像传给native处理,如何传递?将bitmap转换成一个 byte[] 方便传递也方便cpp代码直接处理图像 ...

  8. Help Hanzo (素数筛+区间枚举)

    Help Hanzo 题意:求a~b间素数个数(1 ≤ a ≤ b < 231, b - a ≤ 100000).     (全题在文末) 题解: a~b枚举必定TLE,普通打表MLE,真是头疼 ...

  9. ABP源码分析二:ABP中配置的注册和初始化

    一般来说,ASP.NET Web应用程序的第一个执行的方法是Global.asax下定义的Start方法.执行这个方法前HttpApplication 实例必须存在,也就是说其构造函数的执行必然是完成 ...

  10. MapReduce剖析笔记之七:Child子进程处理Map和Reduce任务的主要流程

    在上一节我们分析了TaskTracker如何对JobTracker分配过来的任务进行初始化,并创建各类JVM启动所需的信息,最终创建JVM的整个过程,本节我们继续来看,JVM启动后,执行的是Child ...