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 相关文章推荐
你需要知道的JavsScript可以做什么?
Jun 29 Javascript
JS input文本框禁用右键和复制粘贴功能的代码
Apr 15 Javascript
一行代码实现纯数据json对象的深度克隆实现思路
Jan 09 Javascript
JavaScript实现仿网易通行证表单验证
May 25 Javascript
jQuery中bind(),live(),delegate(),on()绑定事件方法实例详解
Jan 19 Javascript
jQuery无缝轮播图代码
Dec 22 Javascript
Vue组件通信实践记录(推荐)
Aug 15 Javascript
Redux实现组合计数器的示例代码
Jul 04 Javascript
BootStrap中的模态框(modal,弹出层)功能示例代码
Nov 02 Javascript
javascript中数组的常用算法深入分析
Mar 12 Javascript
element-ui组件中input等的change事件中传递自定义参数
May 22 Javascript
编写更好的JavaScript条件式和匹配条件的技巧(小结)
Jun 27 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封装的XML简单操作类完整实例
2017/11/13 PHP
PHP反射原理与用法深入分析
2019/09/28 PHP
JQuery从头学起第一讲
2010/07/04 Javascript
javascript 伪数组实现方法
2010/10/11 Javascript
JQquery的一些使用心得分享
2012/08/01 Javascript
查找iframe里元素的方法可传参
2013/09/11 Javascript
简述JavaScript中正则表达式的使用方法
2015/06/15 Javascript
JS弹出对话框实现方法(三种方式)
2015/12/18 Javascript
原生javascript实现自动更新的时间日期
2016/02/12 Javascript
Bootstrap中CSS的使用方法
2016/02/17 Javascript
jQuery绑定事件的四种方式介绍
2016/10/31 Javascript
基于Javascript倒计时效果
2016/12/22 Javascript
Vue + Webpack + Vue-loader学习教程之相关配置篇
2017/03/14 Javascript
Agularjs妙用双向数据绑定实现手风琴效果
2017/05/26 Javascript
Angular将填入表单的数据渲染到表格的方法
2017/09/22 Javascript
vue组件定义,全局、局部组件,配合模板及动态组件功能示例
2019/03/19 Javascript
javascript面向对象三大特征之封装实例详解
2019/07/24 Javascript
layui表格内容溢出的解决方法
2019/09/06 Javascript
浅谈Vue.js之初始化el以及数据的绑定说明
2019/11/14 Javascript
javascript实现视频弹幕效果(两个版本)
2019/11/28 Javascript
原生js实现轮播图特效
2020/05/04 Javascript
vue+Element-ui前端实现分页效果
2020/11/15 Javascript
[02:51]DOTA2战队出征照拍摄花絮 TI3明星化身时尚男模
2013/07/22 DOTA
windows下安装python paramiko模块的代码
2013/02/10 Python
浅谈Python中带_的变量或函数命名
2017/12/04 Python
浅谈Python实现2种文件复制的方法
2018/01/19 Python
对Python3 pyc 文件的使用详解
2019/02/16 Python
详解Python中pandas的安装操作说明(傻瓜版)
2019/04/08 Python
利用Python裁切tiff图像且读取tiff,shp文件的实例
2020/03/10 Python
matplotlib 三维图表绘制方法简介
2020/09/20 Python
全面总结使用CSS实现水平垂直居中效果的方法
2016/03/10 HTML / CSS
北京鼎普科技股份有限公司软件测试面试题
2012/04/07 面试题
好人好事演讲稿
2014/09/01 职场文书
上课不认真检讨书
2014/09/17 职场文书
《颐和园》教学反思
2016/02/19 职场文书
浅谈Redis位图(Bitmap)及Redis二进制中的问题
2021/07/15 Redis