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设置FieldSet展开与收缩
May 15 Javascript
多浏览器兼容的获取元素和鼠标的位置的js代码
Dec 15 Javascript
JavaScript中的Primitive对象封装介绍
Dec 31 Javascript
javascript图片预加载完整实例
Dec 10 Javascript
jQuery Html控件基本操作(日常收集整理)
Mar 11 Javascript
JavaScript弹窗基础篇
Apr 27 Javascript
利用js编写响应式侧边栏
Sep 17 Javascript
基于jQuery实现顶部导航栏功能
Dec 27 Javascript
JQ中$(window).load和$(document).ready区别与执行顺序
Mar 01 Javascript
vue-cli项目修改文件热重载失效的解决方法
Sep 19 Javascript
vue中对象数组去重的实现
Feb 06 Javascript
node事件循环和process模块实例分析
Feb 14 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
2006/12/14 PHP
PHP函数extension_loaded()用法实例
2015/01/19 PHP
PHP提取字符串中的手机号正则表达式怎么写
2017/07/17 PHP
JavaScript制作淘宝星级评分效果的思路
2020/06/23 Javascript
JS判断当前页面是否在微信浏览器打开的方法
2015/12/08 Javascript
jquery 禁止鼠标右键并监听右键事件
2017/04/27 jQuery
Webpack如何引入bootstrap的方法
2017/06/17 Javascript
jQuery实现DIV响应鼠标滑过由下向上展开效果示例【测试可用】
2018/04/26 jQuery
解决node修改后需频繁手动重启的问题
2018/05/13 Javascript
bootstrapTable+ajax加载数据 refresh更新数据
2018/08/31 Javascript
JS编写兼容IE6,7,8浏览器无缝自动轮播
2018/10/12 Javascript
vue车牌号校验和银行校验实战
2019/01/23 Javascript
layui switch 开关监听 弹出确定状态转换的例子
2019/09/21 Javascript
[01:32]2016国际邀请赛中国区预选赛IG战队首日赛后采访
2016/06/27 DOTA
python中学习K-Means和图片压缩
2017/11/20 Python
python删除某个字符
2018/03/19 Python
python实现简单的文字识别
2018/11/27 Python
在Python文件中指定Python解释器的方法
2019/02/18 Python
学python安装的软件总结
2019/10/12 Python
python 经典数字滤波实例
2019/12/16 Python
matplotlib 曲线图 和 折线图 plt.plot()实例
2020/04/17 Python
Python 实现集合Set的示例
2020/12/21 Python
美国机场停车位预订:About Airport Parking
2018/03/26 全球购物
单身旅行者的单身假期:Just You
2018/04/08 全球购物
舞会礼服和舞会鞋:PromGirl
2019/04/22 全球购物
印度排名第一的蛋糕、鲜花和礼品送货:Winni
2019/08/02 全球购物
南京迈特望C/C++面试题
2012/07/09 面试题
thinkphp5 redis缓存新增方法实例讲解
2021/03/24 PHP
教师自我评价范例
2013/09/24 职场文书
师范生实习自我鉴定
2013/11/01 职场文书
应届生人事助理求职信
2013/11/09 职场文书
中学教师管理制度
2014/01/14 职场文书
青年标兵事迹材料
2014/08/16 职场文书
施工安全责任协议书
2016/03/23 职场文书
教你用Python+selenium搭建自动化测试环境
2021/06/18 Python
怎么禁用Win11输入法 最新Win11输入法关闭教程
2022/08/05 数码科技