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 相关文章推荐
jQuery瀑布流插件Wookmark使用实例
Apr 02 Javascript
JavaScript使用yield模拟多线程的方法
Mar 19 Javascript
javascript实现网页中涉及的简易运动(改变宽高、透明度、位置)
Nov 29 Javascript
JavaScript实现倒计时跳转页面功能【实用】
Dec 13 Javascript
bootstrap提示标签、提示框实现代码
Dec 28 Javascript
jQuery Ajax 实现在html页面实时显示用户登录状态
Dec 30 Javascript
原生js实现水平方向无缝滚动
Jan 10 Javascript
jQuery实现动态生成表格并为行绑定单击变色动作的方法
Apr 17 jQuery
JS实现左边列表移到到右边列表功能
Mar 28 Javascript
微信小程序实现省市区三级地址选择
Jun 21 Javascript
jQuery实现动态添加和删除input框实例代码
Mar 26 jQuery
在vue中使用jsx语法的使用方法
Sep 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
文章推荐系统(三)
2006/10/09 PHP
用php+mysql一个名片库程序
2006/10/09 PHP
PHP简单实现“相关文章推荐”功能的方法
2014/07/19 PHP
thinkPHP学习笔记之安装配置篇
2015/03/05 PHP
解决PHP程序运行时:Fatal error: Maximum execution time of 30 seconds exceeded in的错误提示
2016/11/25 PHP
PHP5.0 TIDY_PARSE_FILE缓冲区溢出漏洞的解决方案
2018/10/14 PHP
javascript preload&amp;lazy load
2010/05/13 Javascript
jquery获取ASP.NET服务器端控件dropdownlist和radiobuttonlist生成客户端HTML标签后的value和text值
2010/06/28 Javascript
html+javascript实现可拖动可提交的弹出层对话框效果
2013/08/05 Javascript
jquery实现省市select下拉框的替换(示例代码)
2014/02/22 Javascript
Javascript基础教程之if条件语句
2015/01/18 Javascript
js实现大转盘抽奖游戏实例
2015/06/24 Javascript
jQuery结合AJAX之在页面滚动时从服务器加载数据
2015/06/30 Javascript
js仿百度登录页实现拖动窗口效果
2016/03/11 Javascript
jquery ajax结合thinkphp的getjson实现跨域的方法
2016/06/06 Javascript
jQuery实现给input绑定回车事件的方法
2017/02/09 Javascript
将 vue 生成的 js 上传到七牛的实例
2017/07/28 Javascript
Angular学习笔记之集成三方UI框架、控件的示例
2018/03/23 Javascript
Vue.js 中 axios 跨域访问错误问题及解决方法
2018/11/21 Javascript
解决vue+ element ui 表单验证有值但验证失败问题
2020/01/16 Javascript
Element Dialog对话框的使用示例
2020/07/26 Javascript
OpenLayers3实现对地图的基本操作
2020/09/28 Javascript
[46:04]Liquid vs VP Supermajor决赛 BO 第四场 6.10
2018/07/05 DOTA
python基于隐马尔可夫模型实现中文拼音输入
2016/04/01 Python
基于Python的接口测试框架实例
2016/11/04 Python
Python基于matplotlib实现绘制三维图形功能示例
2018/01/18 Python
Python管理Windows服务小脚本
2018/03/12 Python
关于numpy.where()函数 返回值的解释
2019/12/06 Python
opencv python图像梯度实例详解
2020/02/04 Python
详解通过HTML5 Canvas实现图片的平移及旋转变化的方法
2016/03/22 HTML / CSS
ProBikeKit英国:在线公路自行车之家
2017/02/10 全球购物
Tahari ASL官方网站:高级设计师女装
2021/03/15 全球购物
研发工程师的岗位职责
2013/11/18 职场文书
火锅店创业计划书范文
2014/02/02 职场文书
外贸采购员岗位职责
2015/04/03 职场文书
面试复试通知单
2015/04/24 职场文书