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 相关文章推荐
用JS实现一个页面多个css样式实现
May 29 Javascript
Jquery下attr和removeAttr的使用方法
Dec 28 Javascript
JS的Document属性和方法小结
Sep 17 Javascript
简单漂亮的js弹窗可自由拖拽且兼容大部分浏览器
Oct 22 Javascript
JavaScript禁止页面操作的示例代码
Dec 17 Javascript
JavaScript中exec函数用法实例分析
Jun 08 Javascript
picLazyLoad 实现图片延时加载(包含背景图片)
Jul 21 Javascript
js获取页面引用的css样式表中的属性值方法(推荐)
Aug 19 Javascript
基于slideout.js实现移动端侧边栏滑动特效
Nov 28 Javascript
Vue.js中组件中的slot实例详解
Jul 17 Javascript
原生js的ajax和解决跨域的jsonp(实例讲解)
Oct 16 Javascript
VUE动态生成word的实现
Jul 26 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,ajax实现分页
2008/03/27 PHP
php 取得瑞年与平年的天数的代码
2009/08/10 PHP
Laravel框架学习笔记之批量更新数据功能
2019/05/30 PHP
浅析JavaScript原型继承的陷阱
2013/12/03 Javascript
JavaScript使用循环和分割来替换和删除元素实例
2014/10/13 Javascript
基于JavaScript实现网页倒计时自动跳转代码
2015/12/28 Javascript
js弹出框、对话框、提示框、弹窗实现方法总结(推荐)
2016/05/31 Javascript
由浅入深剖析Angular表单验证
2016/07/14 Javascript
Google 地图获取API Key详细教程
2016/08/06 Javascript
angularjs指令之绑定策略(@、=、&amp;)
2017/04/13 Javascript
JS给按钮添加跳转功能类似a标签
2017/05/30 Javascript
jQuery+C#实现参数RSA加密传输功能【附jsencrypt.js下载】
2017/06/26 jQuery
解决淘宝cnpm 安装后cnpm不是内部或外部命令的问题
2018/05/17 Javascript
点击按钮弹出模态框的一系列操作代码实例
2019/03/29 Javascript
详解vue中使用vue-quill-editor富文本小结(图片上传)
2019/04/24 Javascript
详解ECMAScript2019/ES10新属性
2019/12/06 Javascript
详解Typescript 内置的模块导入兼容方式
2020/05/31 Javascript
JS实现购物车基本功能
2020/11/08 Javascript
JavaScript实现点击图片换背景
2020/11/20 Javascript
python 提取文件的小程序
2009/07/29 Python
删除目录下相同文件的python代码(逐级优化)
2012/05/25 Python
python 进程 进程池 进程间通信实现解析
2019/08/23 Python
在OpenCV里使用特征匹配和单映射变换的代码详解
2019/10/23 Python
python3中rank函数的用法
2019/11/27 Python
tensorflow 重置/清除计算图的实现
2020/01/19 Python
解决Django部署设置Debug=False时xadmin后台管理系统样式丢失
2020/04/07 Python
Python图像阈值化处理及算法比对实例解析
2020/06/19 Python
沙特阿拉伯电子产品和家用电器购物网站:Black Box
2019/07/24 全球购物
Laravel的加密解密与哈希实例讲解
2021/03/24 PHP
CSS代码检查工具stylelint的使用方法详解
2021/03/27 HTML / CSS
学校募捐倡议书
2014/05/14 职场文书
学习优秀共产党员先进事迹思想报告
2014/09/17 职场文书
高中生第一学年自我鉴定2015
2014/09/28 职场文书
文化大革命观后感
2015/06/17 职场文书
小学二年级语文教学反思
2016/03/03 职场文书
Pytorch反向传播中的细节-计算梯度时的默认累加操作
2021/06/05 Python