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 相关文章推荐
javascript setTimeout和setInterval计时的区别详解
Jun 21 Javascript
jquery+ajax+C#实现无刷新操作数据库数据的简单实例
Feb 08 Javascript
JavaScript检查某个function是否是原生代码的方法
Aug 20 Javascript
在Node.js应用中使用Redis的方法简介
Jun 24 Javascript
浅析JSONP技术原理及实现
Jun 08 Javascript
JS实现的幻灯片切换显示效果
Sep 07 Javascript
js判断出两个字符串最大子串的函数实现方法
Nov 01 Javascript
js实现年月日表单三级联动
Apr 17 Javascript
vue router 通过路由来实现切换头部标题功能
Apr 24 Javascript
node实现socket链接与GPRS进行通信的方法
May 20 Javascript
react的hooks的用法详解
Oct 12 Javascript
vue登录页实现使用cookie记住7天密码功能的方法
Feb 18 Vue.js
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
通过ICQ网关发送手机短信的PHP源程序
2006/10/09 PHP
Laravel 5框架学习之表单
2015/04/08 PHP
php获取文章内容第一张图片的方法示例
2017/07/03 PHP
PHP基于DateTime类解决Unix时间戳与日期互转问题【针对1970年前及2038年后时间戳】
2018/06/13 PHP
js中widow.open()方法使用详解
2013/07/30 Javascript
用jquery写的一个万年历(自写)
2014/01/20 Javascript
js判断60秒以及倒计时示例代码
2014/01/24 Javascript
js实现跟随鼠标移动且带关闭功能的图片广告实例
2015/02/26 Javascript
jQuery实现在下拉列表选择时获取json数据的方法
2015/04/16 Javascript
jQuery的css() 方法使用指南
2015/05/03 Javascript
JavaScript实现跨浏览器的添加及删除事件绑定函数实例
2015/08/04 Javascript
基于jQuery实现的扇形定时器附源码下载
2015/10/20 Javascript
jQuery事件绑定用法详解(附bind和live的区别)
2016/01/19 Javascript
拥有一个属于自己的javascript表单验证插件
2016/03/24 Javascript
Bootstrap3 Grid system原理及应用详解
2016/09/30 Javascript
JavaScript实现垂直向上无缝滚动特效代码
2016/11/23 Javascript
node.js中实现kindEditor图片上传功能的方法教程
2017/04/26 Javascript
详解webpack进阶之插件篇
2017/07/06 Javascript
webpack构建vue项目的详细教程(配置篇)
2017/07/17 Javascript
angularjs的单选框+ng-repeat的实现方法
2018/09/12 Javascript
为什么说JavaScript预解释是一种毫无节操的机制详析
2018/11/18 Javascript
微信小程序MUI导航栏透明渐变功能示例(通过改变rgba的a值实现)
2019/01/24 Javascript
使用 vue 实例更好的监听事件及vue实例的方法
2019/04/22 Javascript
TypeScript之调用栈的实现
2019/12/31 Javascript
[01:55]2014DOTA2国际邀请赛 BBC正赛第一天总结
2014/07/10 DOTA
python根据出生年份简单计算生肖的方法
2015/03/27 Python
python简单区块链模拟详解
2019/07/03 Python
django的403/404/500错误自定义页面的配置方式
2020/05/21 Python
PHP经典面试题
2016/09/03 面试题
教师演讲稿范文
2014/01/08 职场文书
《黄河颂》教学反思
2014/02/07 职场文书
商铺租房协议书范本
2014/12/04 职场文书
2014年减负工作总结
2014/12/10 职场文书
2015财务年度工作总结范文
2015/05/04 职场文书
MySQL CHAR和VARCHAR该如何选择
2021/05/31 MySQL
Netty分布式客户端处理接入事件handle源码解析
2022/03/25 Java/Android