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 相关文章推荐
创建一个复制UBB软件信息的链接或按钮的js代码
Jan 06 Javascript
javaScript 简单验证代码(用户名,密码,邮箱)
Sep 28 Javascript
js parentElement和offsetParent之间的区别
Mar 23 Javascript
基于jQuery的让非HTML5浏览器支持placeholder属性的代码
May 24 Javascript
Javascript原型链的原理详解
Jan 05 Javascript
jQuery实现简单隔行变色的方法
Feb 20 Javascript
JavaScript数组操作函数汇总
Aug 05 Javascript
原生js实现addclass,removeclass,toggleclasss实例
Nov 24 Javascript
有趣的bootstrap走动进度条
Dec 01 Javascript
jsonp跨域请求实现示例
Mar 13 Javascript
Bootstrap学习笔记 轮播(Carousel)插件
Mar 21 Javascript
ES6中的Javascript解构的实现
Oct 30 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
thinkphp区间查询、统计查询与SQL直接查询实例分析
2014/11/24 PHP
php+ajax制作无刷新留言板
2015/10/27 PHP
非常不错的一个javascript 类
2006/11/07 Javascript
js setattribute批量设置css样式
2009/11/26 Javascript
jQuery实现form表单reset按钮重置清空表单功能
2012/12/18 Javascript
JS图片自动轮换效果实现思路附截图
2014/04/30 Javascript
js实现匹配时换色的输入提示特效代码
2015/08/17 Javascript
javascript拖拽应用实例
2016/03/25 Javascript
AngularJs入门教程之环境搭建+创建应用示例
2016/11/01 Javascript
微信小程序 简单DEMO布局,逻辑,样式的练习
2016/11/30 Javascript
jQuery弹出窗口打开链接的实现代码
2016/12/24 Javascript
使用openSpeDiv方法实现Ecshop登录弹窗框效果
2017/03/13 Javascript
Vue 页面状态保持页面间数据传输的一种方法(推荐)
2018/11/01 Javascript
jquery UI实现autocomplete在获取焦点时得到显示列表功能示例
2019/06/04 jQuery
vue实现手机端省市区区域选择
2019/09/27 Javascript
vue从零实现一个消息通知组件的方法详解
2020/03/16 Javascript
Javascript实现鼠标移入方向感知
2020/06/24 Javascript
[45:40]Ti4 冒泡赛第二天NEWBEE vs NaVi 1
2014/07/15 DOTA
[00:35]DOTA2上海特级锦标赛 Newbee战队宣传片
2016/03/03 DOTA
利用Tkinter(python3.6)实现一个简单计算器
2017/12/21 Python
Python 类的特殊成员解析
2018/06/20 Python
详解用python自制微信机器人,定时发送天气预报
2019/03/25 Python
Python 中的 global 标识对变量作用域的影响
2019/08/12 Python
Python json模块与jsonpath模块区别详解
2020/03/05 Python
Python+OpenCV图像处理—— 色彩空间转换
2020/10/22 Python
英国花园家具中心:Garden Furniture Centre
2017/08/24 全球购物
人力资源经理自我评价
2014/01/04 职场文书
微笑面对生活演讲稿
2014/05/13 职场文书
党员演讲稿
2014/09/04 职场文书
行政工作试用期自我评价
2014/09/14 职场文书
父亲去世追悼词
2015/06/23 职场文书
导游词之桂林
2019/08/20 职场文书
CocosCreator ScrollView优化系列之分帧加载
2021/04/14 Python
zabbix监控mysql的实例方法
2021/06/02 MySQL
javascript之Object.assign()的痛点分析
2022/03/03 Javascript
pytorch中的 .view()函数的用法介绍
2022/03/17 Python