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 相关文章推荐
jquery中页面Ajax方法$.load的功能使用介绍
Oct 20 Javascript
JavaScript把数组作为堆栈使用的方法
Mar 20 Javascript
jQuery+CSS3实现3D立方体旋转效果
Nov 10 Javascript
AngularJS手动表单验证
Feb 01 Javascript
jQuery基础的工厂函数以及定时器的经典实例分析
May 20 Javascript
Bootstrap table表格简单操作
Feb 07 Javascript
AngularJS中$http的交互问题
Mar 29 Javascript
详解Angular-Cli中引用第三方库
May 21 Javascript
使用vue-cli打包过程中的步骤以及问题的解决
May 08 Javascript
Vue 开发音乐播放器之歌手页右侧快速入口功能
Aug 08 Javascript
监控微信小程序中的慢HTTP请求过程详解
Jul 05 Javascript
详解JavaScript中的执行上下文及调用堆栈
Apr 29 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
setTimeout与setInterval在不同浏览器下的差异
2010/01/24 Javascript
广泛收集的jQuery拖放插件集合
2012/04/09 Javascript
javascript中文本框中输入法切换的问题
2013/12/10 Javascript
原生js与jQuery实现简单的tab切换特效对比
2015/07/30 Javascript
vueJS简单的点击显示与隐藏的效果【实现代码】
2016/05/03 Javascript
完美解决IE不支持Data.parse()的问题
2016/11/24 Javascript
jQuery实现动态添加tr到table的方法
2016/12/26 Javascript
npm国内镜像 安装失败的几种解决方案
2017/06/04 Javascript
JS中正则表达式要注意lastIndex属性
2017/08/08 Javascript
js防刷新的倒计时代码 js倒计时代码
2017/09/06 Javascript
js中this对象用法分析
2018/01/05 Javascript
python多线程用法实例详解
2015/01/15 Python
Python2中的raw_input() 与 input()
2015/06/12 Python
python验证码识别教程之利用投影法、连通域法分割图片
2018/06/04 Python
解决Python中定时任务线程无法自动退出的问题
2019/02/18 Python
Python 使用指定的网卡发送HTTP请求的实例
2019/08/21 Python
Python过滤掉numpy.array中非nan数据实例
2020/06/08 Python
mac安装python3后使用pip和pip3的区别说明
2020/09/01 Python
英国领先的葡萄酒专家:Majestic Wine
2017/05/30 全球购物
中国一家专注拼团的社交购物网站:拼多多
2018/06/13 全球购物
GWebs公司笔试题
2012/05/04 面试题
应届毕业生自我评价分享
2013/12/15 职场文书
建筑项目策划书
2014/01/13 职场文书
冰淇淋店的创业计划书
2014/02/07 职场文书
教师竞聘演讲稿
2014/05/16 职场文书
孝老爱亲模范事迹材料
2014/05/25 职场文书
绵山导游词
2015/02/05 职场文书
市场部岗位职责
2015/02/12 职场文书
我们的节日中秋节活动总结
2015/03/23 职场文书
公司的力量观后感
2015/06/05 职场文书
欠条范文
2015/07/03 职场文书
2015秋季开学典礼新闻稿
2015/07/17 职场文书
祝酒词范文
2015/08/12 职场文书
Python可变集合和不可变集合的构造方法大全
2021/12/06 Python
漫画「日和酱的要求是绝对的」第3卷封面公开
2022/03/21 日漫
Java实现字符串转为驼峰格式的方法详解
2022/07/07 Java/Android