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 相关文章推荐
js Html结构转字符串形式显示代码
Nov 15 Javascript
jquery中dom操作和事件的实例学习-表单验证
Nov 30 Javascript
JavaScript创建一个欢迎cookie弹出窗实现代码
Mar 15 Javascript
JavaScript SHA512&amp;SHA256加密算法详解
Aug 11 Javascript
简介alert()与console.log()的不同
Aug 26 Javascript
Bootstrap Validator 表单验证
Jul 25 Javascript
浅谈js函数三种定义方式 &amp; 四种调用方式 &amp; 调用顺序
Feb 19 Javascript
JS中Object对象的原型概念基础
Jan 29 Javascript
vue动态配置模板 'component is'代码
Jul 04 Javascript
vue-next/runtime-core 源码阅读指南详解
Oct 25 Javascript
JavaScript异步操作的几种常见处理方法实例总结
May 11 Javascript
10分钟学会js处理json的常用方法
Dec 06 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
PHP中文件上传的一个问题
2010/09/04 PHP
ThinkPHP添加更新标签的方法
2014/12/05 PHP
PHP生成静态HTML页面最简单方法示例
2015/04/09 PHP
关于php中的json_encode()和json_decode()函数的一些说明
2016/11/20 PHP
jquery 的 $(&quot;#id&quot;).html() 无内容的解决方法
2010/06/07 Javascript
Javascript倒计时页面跳转实例小结
2013/09/11 Javascript
javascript上下方向键控制表格行选中并高亮显示的方法
2015/02/13 Javascript
javascript无刷新评论实现方法
2015/05/13 Javascript
JS实现从连接中获取youtube的key实例
2015/07/02 Javascript
Vue表单实例代码
2016/09/05 Javascript
loading动画特效小结
2017/01/22 Javascript
BootStrap Select清除选中的状态恢复默认状态
2017/06/20 Javascript
nodejs构建本地web测试服务器 如何解决访问静态资源问题
2017/07/14 NodeJs
vue-cli脚手架config目录下index.js配置文件的方法
2018/03/13 Javascript
Vue使用mixins实现压缩图片代码
2018/03/14 Javascript
node解析修改nginx配置文件操作实例分析
2019/11/06 Javascript
JS实现星星海特效
2019/12/24 Javascript
解决idea开发遇到javascript动态添加html元素时中文乱码的问题
2020/09/29 Javascript
[53:13]2014 DOTA2国际邀请赛中国区预选赛5.21 DT VS LGD-GAMING
2014/05/22 DOTA
[37:47]IG vs Winstrike 2018国际邀请赛小组赛BO2 第二场 8.19
2018/08/21 DOTA
python利用datetime模块计算时间差
2015/08/04 Python
安装python3的时候就是输入python3死活没有反应的解决方法
2018/01/24 Python
Python队列、进程间通信、线程案例
2019/10/25 Python
tensorflow 固定部分参数训练,只训练部分参数的实例
2020/01/20 Python
python文件操作seek()偏移量,读取指正到指定位置操作
2020/07/05 Python
python如何写try语句
2020/07/14 Python
欧洲顶级的童装奢侈品购物网站:Bambini Fashion(面向全球)
2018/04/24 全球购物
Gap英国官网:Gap UK
2018/07/18 全球购物
介绍一下常见的木马种类
2014/11/15 面试题
实习教师自我鉴定
2013/12/09 职场文书
学期自我评价
2014/01/27 职场文书
教师自我反思材料
2014/02/14 职场文书
团支部推优材料
2014/05/21 职场文书
会计实训总结范文
2015/08/03 职场文书
Python带你从浅入深探究Tuple(基础篇)
2021/05/15 Python
PHP中多字节字符串操作实例详解
2021/08/23 PHP