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 相关文章推荐
让innerHTML的脚本也可以运行起来
Jul 01 Javascript
javascript函数以及基础写法100多条实用整理
Jan 13 Javascript
JS简单实现元素复制示例附图
Nov 19 Javascript
javascript中文本框中输入法切换的问题
Dec 10 Javascript
js禁止回车提交表单的示例代码
Dec 23 Javascript
javascript实现在线客服效果
Jul 15 Javascript
javascript设计模式之module(模块)模式
Aug 19 Javascript
jQuery实现邮箱下拉列表自动补全功能
Sep 08 Javascript
AjaxUpLoad.js实现文件上传
Mar 05 Javascript
js获取html页面代码中图片地址的实现代码
Mar 05 Javascript
Async/Await替代Promise的6个理由
Jun 15 Javascript
vue3为什么要用proxy替代defineProperty
Oct 19 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
一个odbc连mssql分页的类
2006/10/09 PHP
PHP取整数函数常用的四种方法小结
2012/07/05 PHP
PHP中把数据库查询结果输出为json格式简单实例
2015/04/09 PHP
smarty中常用方法实例总结
2015/08/07 PHP
用js写了一个类似php的print_r输出换行功能
2013/02/18 Javascript
httpclient模拟登陆具体实现(使用js设置cookie)
2013/12/11 Javascript
浅谈Javascript中substr和substring的区别
2015/09/30 Javascript
window.close(); 关闭浏览器窗口js代码的总结介绍
2016/07/14 Javascript
浅析JavaScript中break、continue和return的区别
2016/11/30 Javascript
深入理解Commonjs规范及Node模块实现
2017/05/17 Javascript
原生JS封装animate运动框架的实例
2017/10/12 Javascript
p5.js入门教程之键盘交互
2018/03/19 Javascript
Vue关于组件化开发知识点详解
2020/05/13 Javascript
Python卸载模块的方法汇总
2016/06/07 Python
python创建列表和向列表添加元素的实现方法
2017/12/25 Python
浅谈python日志的配置文件路径问题
2018/04/28 Python
python远程连接服务器MySQL数据库
2018/07/02 Python
浅谈Python脚本开头及导包注释自动添加方法
2018/10/27 Python
Python中文编码知识点
2019/02/18 Python
python使用celery实现异步任务执行的例子
2019/08/28 Python
Tensorflow 模型转换 .pb convert to .lite实例
2020/02/12 Python
Python递归求出列表(包括列表中的子列表)的最大值实例
2020/02/27 Python
Python json转字典字符方法实例解析
2020/04/13 Python
Python openpyxl 插入折线图实例
2020/04/17 Python
python实现xlwt xlrd 指定条件给excel行添加颜色
2020/07/14 Python
浅析Python 字符编码与文件处理
2020/09/24 Python
AC Lens:购买隐形眼镜
2017/02/26 全球购物
会计系毕业个人自荐信格式
2013/09/23 职场文书
交通事故检查书范文
2014/01/30 职场文书
优秀大学生求职自荐信范文
2014/04/19 职场文书
食品安全承诺书
2014/05/22 职场文书
2014国庆节幼儿园亲子活动方案
2014/09/16 职场文书
退休党员个人对照检查材料思想汇报
2014/09/29 职场文书
入党团支部推荐意见
2015/06/02 职场文书
nginx如何将http访问的网站改成https访问
2021/03/31 Servers
Vue的生命周期一起来看看
2022/02/24 Vue.js