JSONP原理及简单实现


Posted in Javascript onJune 08, 2016

在web2.0时代,熟练的使用ajax是每个前端攻城师必备的技能。然而由于受到浏览器的限制,ajax不允许跨域通信。

JSONP就是目前主流的实现跨域通信的解决方案。

虽然在在jquery中,我们可以通过$.ajax的dataType设置为jsonp来调用jsonp,但是jsonp和ajax的实现原理一个关系都木有。jsonp主要是通过script可以链接远程url来实现跨域请求的。如:

<script src="http://jsonp.js?callback=xxx"></script>

callback定义了一个函数名,而远程服务端通过调用指定的函数并传入参数来实现传递参数。

搜索了网上好多文章,他们实现方法都过于简单,要实际应用还要多加修改,我在这里封装了一个对象,可以直接运用于实际操作。

var JSONP = {
// 获取当前时间戳
now: function() {
return (new Date()).getTime();
},
// 获取16位随机数
rand: function() {
return Math.random().toString().substr(2);
},
// 删除节点元素
removeElem: function(elem) {
var parent = elem.parentNode;
if(parent && parent.nodeType !== 11) {
parent.removeChild(elem);
}
},
// url组装
parseData: function(data) {
var ret = "";
if(typeof data === "string") {
ret = data;
}
else if(typeof data === "object") {
for(var key in data) {
ret += "&" + key + "=" + encodeURIComponent(data[key]);
}
}
// 加个时间戳,防止缓存
ret += "&_time=" + this.now();
ret = ret.substr(1);
return ret;
},
getJSON: function(url, data, func) {
// 函数名称
var name;
// 拼装url
url = url + (url.indexOf("?") === -1 ? "?" : "&") + this.parseData(data);
// 检测callback的函数名是否已经定义
var match = /callback=(\w+)/.exec(url);
if(match && match[1]) {
name = match[1];
} else {
// 如果未定义函数名的话随机成一个函数名
// 随机生成的函数名通过时间戳拼16位随机数的方式,重名的概率基本为0
// 如:jsonp_1355750852040_8260732076596469
name = "jsonp_" + this.now() + '_' + this.rand();
// 把callback中的?替换成函数名
url = url.replace("callback=?", "callback="+name);
// 处理?被encode的情况
url = url.replace("callback=%3F", "callback="+name);
}
// 创建一个script元素
var script = document.createElement("script");
script.type = "text/javascript";
// 设置要远程的url
script.src = url;
// 设置id,为了后面可以删除这个元素
script.id = "id_" + name;
// 把传进来的函数重新组装,并把它设置为全局函数,远程就是调用这个函数
window[name] = function(json) {
// 执行这个函数后,要销毁这个函数
window[name] = undefined;
// 获取这个script的元素
var elem = document.getElementById("id_" + name);
// 删除head里面插入的script,这三步都是为了不影响污染整个DOM啊
JSONP.removeElem(elem);
// 执行传入的的函数
func(json);
};
// 在head里面插入script元素
var head = document.getElementsByTagName("head");
if(head && head[0]) {
head[0].appendChild(script);
}
}
};

实现过程基本写在注释里啦,自己看。调用的方法跟jQuery基本一样。如:

var data = {
from: "北京",
count: 27,
output: "json",
callback: "?"
}
JSONP.getJSON("http://api.qunar.com/cdnWebservices.jcp", data, function(json) {console.log(json)});

当然要这么写也行:

JSONP.getJSON("http://api.qunar.com/cdnWebservices.jcp?from=北京&count=27&output=json&callback=?", null, function(json) {console.log(json)});

至于服务端的实现,那就比较简单了,以php为例:

$callback = !empty($_GET['callback']) ? $_GET['callback'] : 'callback';
echo $callback.'( .json_encode( $data ).')';

ajax与jsonp的异同再做一些补充说明:

1、ajax和jsonp这两种技术在调用方式上“看起来”很像,目的也一样,都是请求一个url,然后把服务器返回的数据进行处理,因此jquery和ext等框架都把jsonp作为ajax的一种形式进行了封装;

2、但ajax和jsonp其实本质上是不同的东西。ajax的核心是通过XmlHttpRequest获取非本页内容,而jsonp的核心则是动态添加<script>标签来调用服务器提供的js脚本。

3、所以说,其实ajax与jsonp的区别不在于是否跨域,ajax通过服务端代理一样可以实现跨域,jsonp本身也不排斥同域的数据的获取。

4、还有就是,jsonp是一种方式或者说非强制性协议,如同ajax一样,它也不一定非要用json格式来传递数据,如果你愿意,字符串都行,只不过这样不利于用jsonp提供公开服务。

总而言之,jsonp不是ajax的一个特例,哪怕jquery等巨头把jsonp封装进了ajax,也不能改变这一点!

好了,写完了,有什么问题欢迎讨论。

Javascript 相关文章推荐
Javascript 变量作用域 两个可能会被忽略的小特性
Mar 23 Javascript
基于PHP+Jquery制作的可编辑的表格的代码
Apr 10 Javascript
javascript中的绑定与解绑函数应用示例
Jun 24 Javascript
jquery遍历数组与筛选数组的方法
Nov 05 Javascript
js获取下拉列表的值和元素个数示例
May 07 Javascript
JQuery boxy插件在IE中边角图片不显示问题的解决
May 20 Javascript
bootstrap布局中input输入框右侧图标点击功能
May 16 Javascript
Bootstrap实现弹性搜索框
Jul 11 Javascript
Bootstrap中表单控件状态(验证状态)
Aug 04 Javascript
canvas实现手机端用来上传用户头像的代码
Oct 20 Javascript
JS触摸与手势事件详解
May 09 Javascript
详解jQuery中的getAll()和cleanData()
Apr 15 jQuery
Javascript必知必会(四)js类型转换
Jun 08 #Javascript
JavaScript必知必会(三) String .的方法来自何方
Jun 08 #Javascript
JavaScript必知必会(二) null 和undefined
Jun 08 #Javascript
JavaScript必知必会(九)function 说起 闭包问题
Jun 08 #Javascript
jQuery+ajax+asp.net获取Json值的方法
Jun 08 #Javascript
jQuery焦点图轮播插件KinSlideshow用法分析
Jun 08 #Javascript
JavaScript必知必会(十) call apply bind的用法说明
Jun 08 #Javascript
You might like
php下使用以下代码连接并测试
2008/04/09 PHP
PHP sprintf()函数用例解析
2011/05/18 PHP
PHP批量生成图片缩略图的方法
2015/06/18 PHP
php文件读取方法实例分析
2015/06/20 PHP
详解php中反射的应用
2016/03/15 PHP
thinkphp框架实现删除和批量删除
2016/06/29 PHP
PHP实现基于面向对象的mysqli扩展库增删改查操作工具类
2017/07/18 PHP
实例解析php的数据类型
2018/10/24 PHP
jQuery lazyload 的重复加载错误以及修复方法
2010/11/19 Javascript
ExtJS中设置下拉列表框不可编辑的方法
2014/05/07 Javascript
如何判断微信内置浏览器(通过User Agent实现)
2014/09/01 Javascript
AngularJS国际化详解及示例代码
2016/08/18 Javascript
web 屏蔽BackSpace键实例代码
2016/12/24 Javascript
微信小程序 picker 组件详解及简单实例
2017/01/10 Javascript
原生JS实现图片翻书效果
2017/02/16 Javascript
谈谈对vue响应式数据更新的误解
2017/08/01 Javascript
JS SetInterval 代码实现页面轮询
2017/08/11 Javascript
vue 使用自定义指令实现表单校验的方法
2018/08/28 Javascript
vue-cli webpack 引入swiper的操作方法
2018/09/15 Javascript
React通过redux-persist持久化数据存储的方法示例
2019/02/14 Javascript
JS可断点续传文件上传实现代码解析
2020/07/30 Javascript
2款Python内存检测工具介绍和使用方法
2014/06/01 Python
django传值给模板, 再用JS接收并进行操作的实例
2018/05/28 Python
如何利用Boost.Python实现Python C/C++混合编程详解
2018/11/08 Python
对python中GUI,Label和Button的实例详解
2019/06/27 Python
利用Pandas和Numpy按时间戳将数据以Groupby方式分组
2019/07/22 Python
python numpy 反转 reverse示例
2019/12/04 Python
Python常用断言函数实例汇总
2020/11/30 Python
5 分钟读懂Python 中的 Hook 钩子函数
2020/12/09 Python
python 日志模块logging的使用场景及示例
2021/01/04 Python
CSS3 仿微信聊天小气泡实例代码
2017/04/05 HTML / CSS
英国最大的化装舞会服装网站:Fancydress.com
2017/08/15 全球购物
审核会计岗位职责
2013/11/08 职场文书
小学生读书感言
2014/02/12 职场文书
2016春季幼儿园大班开学寄语
2015/12/03 职场文书
营销策划分析:怎么策划才能更好销量产品?
2019/09/04 职场文书