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 相关文章推荐
让GoogleCode的SVN下的HTML文件在FireFox下正常显示.
May 25 Javascript
Js+Flash实现访问剪切板操作
Nov 20 Javascript
jquery 实现上下滚动效果示例代码
Aug 09 Javascript
文本域光标操作的jQuery扩展分享
Mar 10 Javascript
JS实现距离上次刷新已过多少秒示例
May 23 Javascript
js实现选项卡内容切换以及折叠和展开效果【推荐】
Jan 08 Javascript
Html5 js实现手风琴效果
Apr 17 Javascript
微信小程序左滑动显示菜单功能的实现
Jun 14 Javascript
基于vue展开收起动画的示例代码
Jul 05 Javascript
jquery实现购物车基本功能
Oct 25 jQuery
JS数组reduce()方法原理及使用技巧解析
Jul 14 Javascript
vue-openlayers实现地图坐标弹框效果
Sep 24 Javascript
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 strtotime 函数UNIX时间戳
2009/01/14 PHP
关于mysql字符集设置了character_set_client=binary 在gbk情况下会出现表描述是乱码的情况
2013/01/06 PHP
php打开文件fopen函数的使用说明
2013/07/05 PHP
php返回json数据函数实例
2014/10/09 PHP
完整删除ecshop中获取店铺信息的API
2014/12/24 PHP
微信公众平台实现获取用户OpenID的方法
2015/04/15 PHP
PHP多个图片压缩成ZIP的方法
2020/08/18 PHP
PHP各种常见经典算法总结【排序、查找、翻转等】
2019/08/05 PHP
laravel框架语言包拓展实现方法分析
2019/11/22 PHP
谷歌浏览器 insertCell与appendChild的区别
2009/02/12 Javascript
jquery中cookie用法实例详解(获取,存储,删除等)
2016/01/04 Javascript
jQuery Validation Engine验证控件调用外部函数验证的方法
2017/01/18 Javascript
原生js实现瀑布流布局
2017/03/08 Javascript
require.js与bootstrap结合实现简单的页面登录和页面跳转功能
2017/05/12 Javascript
移动端效果之Swiper详解
2017/10/09 Javascript
在vue中使用jointjs的方法
2018/03/24 Javascript
30分钟精通React今年最劲爆的新特性——React Hooks
2019/03/11 Javascript
vue iview的菜单组件Mune 点击不高亮的解决方案
2019/11/01 Javascript
在树莓派2或树莓派B+上安装Python和OpenCV的教程
2015/03/30 Python
Python实现截屏的函数
2015/07/25 Python
Python运行报错UnicodeDecodeError的解决方法
2016/06/07 Python
基于Django的ModelForm组件(详解)
2017/12/07 Python
Python中文件的读取和写入操作
2018/04/27 Python
python抓取京东小米8手机配置信息
2018/11/13 Python
Python获取航线信息并且制作成图的讲解
2019/01/03 Python
python+requests接口压力测试500次,查看响应时间的实例
2020/04/30 Python
django 数据库返回queryset实现封装为字典
2020/05/19 Python
python如何更新包
2020/06/11 Python
如何使用canvas绘制可移动网格的示例代码
2020/12/14 HTML / CSS
执行力心得体会
2013/12/31 职场文书
2014年最新学习全国两会精神心得
2014/03/17 职场文书
年终总结会主持词
2014/03/25 职场文书
读书活动总结
2014/04/28 职场文书
党校党性分析材料
2014/12/19 职场文书
保险内勤岗位职责
2015/04/13 职场文书
色戒观后感
2015/06/12 职场文书