jQuery-1.9.1源码分析系列(十六)ajax——jsonp原理
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原理的更多相关文章
- Spring Ioc源码分析系列--@Autowired注解的实现原理
Spring Ioc源码分析系列--@Autowired注解的实现原理 前言 前面系列文章分析了一把Spring Ioc的源码,是不是云里雾里,感觉并没有跟实际开发搭上半毛钱关系?看了一遍下来,对我的 ...
- ABP源码分析二十六:核心框架中的一些其他功能
本文是ABP核心项目源码分析的最后一篇,介绍一些前面遗漏的功能 AbpSession AbpSession: 目前这个和CLR的Session没有什么直接的联系.当然可以自定义的去实现IAbpSess ...
- ABP源码分析三十六:ABP.Web.Api
这里的内容和ABP 动态webapi没有关系.除了动态webapi,ABP必然是支持使用传统的webApi.ABP.Web.Api模块中实现了一些同意的基础功能,以方便我们创建和使用asp.net w ...
- ABP源码分析四十六:ABP ZERO中的Ldap模块
通过AD作为用户认证的数据源.整个管理用户认证逻辑就在LdapAuthenticationSource类中实现. LdapSettingProvider:定义LDAP的setting和提供Defaut ...
- Android源码分析(十六)----adb shell 命令进行OTA升级
一: 进入shell命令界面 adb shell 二:创建目录/cache/recovery mkdir /cache/recovery 如果系统中已有此目录,则会提示已存在. 三: 修改文件夹权限 ...
- spark 源码分析之十六 -- Spark内存存储剖析
上篇spark 源码分析之十五 -- Spark内存管理剖析 讲解了Spark的内存管理机制,主要是MemoryManager的内容.跟Spark的内存管理机制最密切相关的就是内存存储,本篇文章主要介 ...
- jQuery-1.9.1源码分析系列(六) 延时对象应用——jQuery.ready
还记不记得jQuery初始化函数jQuery.fn.init中有这样是一个分支 //document ready简便写法$(function(){…}) } else if ( jQuery.isFu ...
- Vue.js 源码分析(二十六) 高级应用 作用域插槽 详解
普通的插槽里面的数据是在父组件里定义的,而作用域插槽里的数据是在子组件定义的. 有时候作用域插槽很有用,比如使用Element-ui表格自定义模板时就用到了作用域插槽,Element-ui定义了每个单 ...
- jQuery-1.9.1源码分析系列(六) 延时对象续——辅助函数jQuery.when
$.when的说明 描述: 提供一种方法来执行一个或多个对象的回调函数,返回这些对象的延时(Deferred)对象. 说明(结合实例和源码): 如果你不传递任何参数, jQuery.when()将返 ...
- jQuery-1.9.1源码分析系列(六) 延时对象
首先我们需要明白延时对象有什么用? 第一个作用,解决时序以及动态添加执行函数的问题. function a(){alert(1)}; function b(){alert(2)}; function ...
随机推荐
- Ajax 概念 分析 举例
Ajax是结合了访问数据库,数据访问,Jquery 可以做页面局部刷新或者说是页面不刷新,我可以让页面不刷新,仅仅是数据的刷新,没有频繁的刷页面,是现在比较常用的一种方式做页面那么它是怎么实现页面无刷 ...
- .Net多线程编程—任务Task
1 System.Threading.Tasks.Task简介 一个Task表示一个异步操作,Task的创建和执行是独立的. 只读属性: 返回值 名称 说明 object AsyncState 表示在 ...
- npm 使用小结
本文内容基于 npm 4.0.5 概述 npm (node package manager),即 node 包管理器.这里的 node 包就是指各种 javascript 库. npm 是随同 Nod ...
- 在DevExpress程序中使用GridView直接录入数据的时候,增加列表选择的功能
在我上篇随笔<在DevExpress程序中使用Winform分页控件直接录入数据并保存>中介绍了在GridView以及在其封装的分页控件上做数据的直接录入的处理,介绍情况下数据的保存和校验 ...
- EC笔记:第4部分:21、必须返回对象时,别返回引用
使用应用可以大幅减少构造函数与析构函数的调用次数,但是引用不可以滥用. 如下: struct St { int a; }; St &func(){ St t; return t; } 在返回t ...
- 微信小程序开发—快速掌握组件及API的方法
微信小程序框架为开发者提供了一系列的组件和API接口. 组件主要完成小程序的视图部分,例如文字.图片显示.API主要完成逻辑功能,例如网络请求.数据存储.音视频播放控制,以及微信开放的微信登录.微信支 ...
- 直播推流端弱网优化策略 | 直播 SDK 性能优化实践
弱网优化的场景 网络直播行业经过一年多的快速发展,衍生出了各种各样的玩法.最早的网络直播是主播坐在 PC 前,安装好专业的直播设备(如摄像头和麦克风),然后才能开始直播.后来随着手机性能的提升和直播技 ...
- Lucene4.4.0 开发之排序
排序是对于全文检索来言是一个必不可少的功能,在实际运用中,排序功能能在某些时候给我们带来很大的方便,比如在淘宝,京东等一些电商网站我们可能通过排序来快速找到价格最便宜的商品,或者通过排序来找到评论数最 ...
- 电脑新建svn仓库
步骤1:安转svg: 注意事项: 安装的时候选择:Modify 安装到以下图片的步骤时: 黄色区域选择: 步骤2:新建svn仓库文件夹(本教程例子:D:\svn-5gpos),选择文件夹右键,点击下图 ...
- SQL字符串函数
LEN() :计算字符串长度(字符的个数.)datalength();//计算字符串所占用的字节数,不属于字符串函数.测试varchar变量与nvarchar变量存储字符串a的区别.见备注1.LOWE ...