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开发随笔一 preventDefault的必要
Nov 25 Javascript
javascript数组操作总结和属性、方法介绍
Apr 05 Javascript
javascript计时器详解
Feb 28 Javascript
JavaScript的事件代理和委托实例分析
Mar 25 Javascript
js实现(全选)多选按钮的方法【附实例】
Mar 30 Javascript
详解JavaScript中的属性和特性
Dec 08 Javascript
jquery validation验证表单插件
Jan 07 Javascript
如何给ss bash 写一个 WEB 端查看流量的页面
Mar 23 Javascript
基于Vue的文字跑马灯组件(npm 组件包)
May 24 Javascript
对于js垃圾回收机制的理解
Sep 14 Javascript
vue项目中jsonp跨域获取qq音乐首页推荐问题
May 30 Javascript
微信小程序开发中var that =this的用法详解
Jan 18 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中cookies使用指南
2007/03/16 PHP
php缩放gif和png图透明背景变成黑色的解决方法
2014/10/14 PHP
浅谈PHP的排列组合(如输入a,b,c 输出他们的全部组合)
2017/03/14 PHP
JavaScript中__proto__与prototype的关系深入理解
2012/12/04 Javascript
JavaScript eval() 函数介绍及应用示例
2014/07/29 Javascript
node.js中的fs.writeFileSync方法使用说明
2014/12/14 Javascript
JS动画效果打开、关闭层的实现方法
2015/05/09 Javascript
JavaScript中var关键字的使用详解
2015/08/14 Javascript
基于JavaScript代码实现微信扫一扫下载APP
2015/12/30 Javascript
js通过keyCode值判断单击键盘上某个键,然后触发指定的事件方法
2017/02/19 Javascript
vue-router 实现导航守卫(路由卫士)的实例代码
2018/09/02 Javascript
Vue请求JSON Server服务器数据的实现方法
2018/11/02 Javascript
微信公众号平台接口开发 菜单管理的实现
2019/08/14 Javascript
Vue中fragment.js使用方法小结
2020/02/17 Javascript
解决VUEX的mapState/...mapState等取值问题
2020/07/24 Javascript
vue项目,代码提交至码云,iconfont的用法说明
2020/07/30 Javascript
python使用os模块的os.walk遍历文件夹示例
2014/01/27 Python
详解Python中的动态属性和特性
2018/04/07 Python
Django项目后台不挂断运行的方法
2019/08/31 Python
django admin后管定制-显示字段的实例
2020/03/11 Python
详解Python中Pyyaml模块的使用
2020/10/08 Python
Selenium获取登录Cookies并添加Cookies自动登录的方法
2020/12/04 Python
css3绘制天猫logo实现代码
2012/11/06 HTML / CSS
使用css3制作登录表单的步骤
2014/04/07 HTML / CSS
详解CSS3中@media的实际使用
2015/08/04 HTML / CSS
css3的动画特效之动画序列(animation)
2017/12/22 HTML / CSS
Sperry官网:帆船鞋创始品牌
2016/09/07 全球购物
波兰家具和室内装饰品购物网站:Vivre
2018/04/10 全球购物
简述安装Slackware Linux系统的过程
2012/05/08 面试题
小学新学期寄语
2014/04/02 职场文书
雏鹰争章活动总结
2014/05/09 职场文书
党章培训心得体会
2014/09/04 职场文书
开学典礼致辞
2015/07/29 职场文书
Python实现生成bmp图像的方法
2021/06/13 Python
Go语言 详解net的tcp服务
2022/04/14 Golang
Windows Server 版本 20H2 于 8 月 9 日停止支持,Win10 版本 21H1 将于 12 月结束支
2022/07/23 数码科技