Jsonp 关键字详解及json和jsonp的区别,ajax和jsonp的区别


Posted in Javascript onDecember 30, 2015

前言

第一次听说jsonp,其实早在2年之前。当时在做一个活动页面的抽奖模块,要从服务端get一个概率,当时什么都不懂,同事说用ajax,我就用ajax,同事说dataType改成jsonp,我就改成jsonp。于是乎活动页面做完了,以后也没有碰到过jsonp,在这期间我一直以为jsonp跟ajax息息相关,是xhr的一种特殊的跨域形式...直到一个月前的一次面试,问到jsonp我被虐成狗,才决定看下jsonp,好吧,原来jsonp也不是很难。

为什么要用jsonp?

相信大家对跨域一定不陌生,对同源策略也同样熟悉。什么,你没听过?没关系,既然是深入浅出,那就从头说起。

假如我写了个index页面,页面里有个请求,请求的是一个json数据(不知道json数据的猛戳JSON简介以及用法汇总),简单思考写下如下代码:

<script src='http://libs.baidu.com/jquery/2.0.0/jquery.min.js'></script>
<script type="text/javascript">
 $.ajax({
 url: 'http://localhost/a.json',
 dataType: "json",
 success: function (data) {
  console.log(data);
 }
 })
</script> 
{
 "name": "hanzichi",
 "age": 10
}

楼主把两个文件都放在wamp下的www文件夹下,ajax请求没有跨域,完美得到结果:

Jsonp 关键字详解及json和jsonp的区别,ajax和jsonp的区别

但是如果我的json文件和index文件不在一个域下,即跨域(不懂跨域的可参考JavaScript 的同源策略)了呢?

试着在wamp下新开个apache端口(不知道怎么开的可参考WampServer下使用多端口访问),将json文件放到该服务端口的文件夹下(楼主设置的端口号为8080,默认的是80端口),试着发送请求: 

<script src='http://libs.baidu.com/jquery/2.0.0/jquery.min.js'></script>
<script type="text/javascript">
 $.ajax({
 url: 'http://localhost:8080/a.json',
 dataType: "json",
 success: function (data) {
  console.log(data);
 }
 })
</script>

Jsonp 关键字详解及json和jsonp的区别,ajax和jsonp的区别

很显然,提示跨域了!怎么搞?这时jsonp就要出马了!

神奇的script标签

与jsonp息息相关的是script标签,而xhr或者说传统意义上的ajax与之没有半毛钱关系!

接着看上面的index.html代码,我们看到页面引用了百度cdn的jquery路径,对于这样的方式我们似乎已经习以为常,但是仔细一想,script标签可是完完全全的跨域的啊...没错,jsonp的实现核心就是利用script标签的跨域能力!于是我们灵机一动,似乎可以这么搞,动态生成一个script标签,把json的url赋值给script的src属性,然后再把这个script标签插入dom里...

<body>
 <script src='http://libs.baidu.com/jquery/2.0.0/jquery.min.js'></script>
 <script type="text/javascript">
 var s = document.createElement('script');
 s.src = 'http://localhost:8080/a.json';
 document.body.appendChild(s);
 </script>
</body>

我们创建了一个script标签,而标签内包裹的内容正是需要的json数据,但是报错如下:

 Jsonp 关键字详解及json和jsonp的区别,ajax和jsonp的区别

原因是因为json数据并不是合法的js语句,把上面的json数据放在一个回调函数中是最简单的方法:

<body>
 <script src='http://libs.baidu.com/jquery/2.0.0/jquery.min.js'></script>
 <script type="text/javascript">
 function jsonpcallback(json) {
  console.log(json);
 }
 var s = document.createElement('script');
 s.src = 'http://localhost:8080/a.json';
 document.body.appendChild(s);
 </script>
</body> 
jsonpcallback({
 "name": "hanzichi",
 "age": 10
});

Jsonp 关键字详解及json和jsonp的区别,ajax和jsonp的区别

当然,这时的a.json文件并不一定要这样命名,改成a.js也不会有一点问题。

而如果是与服务端交互也是一样的道理,比如和php:

<body>
 <script src='http://libs.baidu.com/jquery/2.0.0/jquery.min.js'></script>
 <script type="text/javascript">
 function jsonpcallback(json) {
  console.log(json);
 }
 var s = document.createElement('script');
 s.src="http://localhost:8080/test.php?callback=jsonpcallback";
 document.body.appendChild(s);
 </script>
</body> 
<?php
 $jsondata = '{
 "name": "hanzichi",
 "age": 10
 }';
 echo $_GET['callback'].'('.$jsondata.')';
?>

需要注意的是,jsonp提供的url(即动态生成的script标签的src),无论看上去是什么形式,最终生成返回的都是一段js代码。

JQuery对jsonp的封装

为了便于开发,jq对jsonp也进行了封装,封装在了ajax方法中。

<script src='http://libs.baidu.com/jquery/2.0.0/jquery.min.js'></script>
<script type="text/javascript">
 $.ajax({
 url: 'http://localhost:8080/a.json',
 dataType: 'jsonp',
 jsonpCallback: 'CallBack',
 success: function (data) {
  console.log(data);
 }
 });
</script> 
CallBack({
 "name": "hanzichi",
 "age": 10
});

以上代码是针对请求文件中写死了callback函数名的情况。因为请求的是json文件,json不是服务器端的动态语言不能进行解析,如果是php或者其他的服务器端语言,则不用写死函数名,比如下面这样:

<script src='http://libs.baidu.com/jquery/2.0.0/jquery.min.js'></script>
<script type="text/javascript">
 $.ajax({
 url: 'http://localhost:8080/test.php',
 dataType: 'jsonp',
 success: function (data) {
  console.log(data);
 }
 });
</script> 
<?php
 $jsondata = '{
 "name": "hanzichi",
 "age": 10
 }';
 echo $_GET['callback'].'('.$jsondata.')';
?>

   当然类似的封装好的方法还有几种:

// 1
$.getJSON("http://localhost:8080/test.php?callback=?", function(data) { 
 console.log(data);
});
// 2
$.get('http://localhost:8080/test.php', function(data) { 
 console.log(data);
}, 'jsonp');

需要注意的是getJSON方法的请求地址url需要带上callback=?,因为jq对该方法进行封装的时候并没有默认回调函数变量名为callback,于是php中$_GET['callback']就找不到变量值了。

而一般的jq方法url 中不用指定 callback 参数。对于 jQuery 中的 jsonp 来说,callback 参数是自动添加的。默认情况下,jQuery 生成的 jsonp 请求中 callback 参数是形如 callback=jQuery200023559735575690866_1434954892929 这种根据看似随机的名字,对应的就是 success 那个处理函数,所以一般不用特意处理。二如果要写死callback名的话,可以参照上文。

 Jsonp 关键字详解及json和jsonp的区别,ajax和jsonp的区别

总结

由于同源策略的限制,XmlHttpRequest只允许请求当前源(域名、协议、端口)的资源,为了实现跨域请求,可以通过script标签实现跨域请求,然后在服务端输出JSON数据并执行回调函数,从而解决了跨域的数据请求,这就是jsonp的核心。

jsonp原理:

 1.首先在客户端注册一个callback, 然后把callback的名字传给服务器。
 2.服务器先生成 json 数据。 然后以 javascript 语法的方式,生成一个function , function 名字就是传递上来的参数 jsonp. 最后将 json 数据直接以入参的方式,放置到 function 中,这样就生成了一段 js 语法的文档,返回给客户端。
 3.客户端浏览器,解析script标签,并执行返回的 javascript 文档,此时数据作为参数,传入到了客户端预先定义好的 callback 函数里.(动态执行回调函数)

 json和jsonp的区别,ajax和jsonp的区别

 json和jsonp虽然只有一个字母的区别,但是它们之间扯不上关系。

json是一种轻量级的数据交换格式。

jsonp是一种跨域数据交互协议。

json的优点:(1)基于纯文本传递极其简单,(2)轻量级数据格式适合互联网传递,(3)容易编写和解析。

ajax和jsonp的区别:

相同点:都是请求一个url

不同点:ajax的核心是通过xmlHttpRequest获取内容

jsonp的核心则是动态添加<script>标签来调用服务器 提供的js脚本。

Javascript 相关文章推荐
checkbox 多选框 联动实现代码
Oct 22 Javascript
JavaScript初学者应注意的七个细节小结
Jan 30 Javascript
javascript 循环调用示例介绍
Nov 20 Javascript
用html+css+js实现的一个简单的图片切换特效
May 28 Javascript
24款热门实用的jQuery插件推荐
Dec 24 Javascript
JS给Textarea文本框添加行号的方法
Aug 20 Javascript
JQuery入门基础小实例(1)
Sep 17 Javascript
javascript动态生成树形菜单的方法
Nov 14 Javascript
Bootstrap 设置datetimepicker在屏幕上面弹出设置方法
Mar 21 Javascript
jQuery无冲突模式详解
Jan 17 jQuery
js+canvas绘制图形验证码
Sep 21 Javascript
浅谈 JavaScript 沙箱Sandbox
Nov 02 Javascript
javascript实现禁止复制网页内容汇总
Dec 30 #Javascript
jquery实现树形菜单完整代码
Dec 29 #Javascript
javascript设置页面背景色及背景图片的方法
Dec 29 #Javascript
js获取及修改网页背景色和字体色的方法
Dec 29 #Javascript
基于JavaScript实现根据手机定位获取当前具体位置(X省X市X县X街道X号)
Dec 29 #Javascript
jQuery中attr()与prop()函数用法实例详解(附用法区别)
Dec 29 #Javascript
使用OpenLayers3 添加地图鼠标右键菜单
Dec 29 #Javascript
You might like
解决laravel groupBy 对查询结果进行分组出现的问题
2019/10/09 PHP
laravel 修改记住我功能的cookie保存时间的方法
2019/10/14 PHP
jquery中动态效果小结
2010/12/16 Javascript
JavaScript日期类型的一些用法介绍
2015/03/02 Javascript
Backbone View 之间通信的三种方式
2016/08/09 Javascript
在页面中引入js的两种方法(推荐)
2017/08/29 Javascript
详解微信小程序Page中data数据操作和函数调用
2017/09/27 Javascript
javascript高仿热血传奇游戏实现代码
2018/02/22 Javascript
AngularJs1.x自定义指令独立作用域的函数传入参数方法
2018/10/09 Javascript
浅析JS中什么是自定义react数据验证组件
2018/10/19 Javascript
[40:04]Secret vs Infamous 2019国际邀请赛淘汰赛 败者组 BO3 第二场 8.23
2019/09/05 DOTA
浅析python 内置字符串处理函数的使用方法
2014/06/11 Python
Python创建系统目录的方法
2015/03/11 Python
python用装饰器自动注册Tornado路由详解
2017/02/14 Python
Python中的__slots__示例详解
2017/07/06 Python
python安装gdal的两种方法
2019/10/29 Python
np.newaxis 实现为 numpy.ndarray(多维数组)增加一个轴
2019/11/30 Python
pytorch中tensor张量数据类型的转化方式
2019/12/31 Python
PyTorch实现重写/改写Dataset并载入Dataloader
2020/07/14 Python
Python字节单位转换(将字节转换为K M G T)
2021/03/02 Python
一些常用的HTML5模式(pattern) 总结
2015/07/14 HTML / CSS
巴黎卡诗美国官方网站:始于1964年的头发头皮护理专家
2017/07/10 全球购物
电子商务专业个人的自我评价
2013/11/19 职场文书
技术总监岗位职责
2013/12/05 职场文书
个人简历中的自我评价怎么写
2014/01/26 职场文书
周年庆典主持词
2014/04/02 职场文书
职员竞岗演讲稿
2014/05/14 职场文书
幼儿园社区活动总结
2014/07/07 职场文书
应聘护士求职信
2014/07/21 职场文书
初中同学会活动方案
2014/08/22 职场文书
综合素质评价个性与发展自我评价
2015/03/06 职场文书
2015年中学体育教师工作总结
2015/10/23 职场文书
党性教育心得体会(共6篇)
2016/01/21 职场文书
优秀员工演讲稿
2019/06/21 职场文书
Python破解极验滑动验证码详细步骤
2021/05/21 Python
JavaScript中reduce()的用法
2022/05/11 Javascript