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 相关文章推荐
取得一定长度的内容,处理中文
Dec 20 Javascript
替代window.event.srcElement效果的可兼容性的函数
Dec 18 Javascript
如何用JavaScript动态呼叫函数(两种方式)
May 03 Javascript
使用JavaScript 实现的人脸检测
Mar 24 Javascript
js实现横向伸展开的二级导航菜单代码
Aug 28 Javascript
JavaScript获取当前运行脚本文件所在目录的方法
Feb 03 Javascript
js老生常谈之this,constructor ,prototype全面解析
Apr 05 Javascript
JS验证图片格式和大小并预览的简单实例
Oct 11 Javascript
js 模仿锚点定位的实现方法
Nov 19 Javascript
Vue 滚动行为的具体使用方法
Sep 13 Javascript
JS中async/await实现异步调用的方法
Aug 28 Javascript
解决vue项目中出现Invalid Host header的问题
Nov 17 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
从Web查询数据库之PHP与MySQL篇
2009/09/25 PHP
创建配置文件 用PHP写出自己的BLOG系统 2
2010/04/12 PHP
php调用方法mssql_fetch_row、mssql_fetch_array、mssql_fetch_assoc和mssql_fetch_objcect读取数据的区别
2012/08/08 PHP
PHP判断文件是否被引入的方法get_included_files用法示例
2016/11/29 PHP
PHP终止脚本运行三种实现方法详解
2020/09/01 PHP
用ASP将SQL搜索出来的内容导出为TXT的代码
2007/07/27 Javascript
Javascript select下拉框操作常用方法
2009/11/09 Javascript
IE本地存储userdata的一个bug说明
2010/07/01 Javascript
文字不间断滚动(上下左右)实例代码
2013/04/21 Javascript
js中settimeout方法加参数
2014/02/28 Javascript
js的参数有长度限制吗?发现不能超过2083个字符
2014/04/20 Javascript
node.js中的buffer.Buffer.isEncoding方法使用说明
2014/12/14 Javascript
JavaScript获取伪元素(Pseudo-Element)属性的方法技巧
2015/03/13 Javascript
浅谈node.js中async异步编程
2015/10/22 Javascript
bootstrap vue.js实现tab效果
2017/02/07 Javascript
简单谈谈gulp-changed插件
2017/02/21 Javascript
vue组件数据传递、父子组件数据获取,slot,router路由功能示例
2019/03/19 Javascript
微信端调取相册和摄像头功能,实现图片上传,并上传到服务器
2019/05/16 Javascript
vue+element table表格实现动态列筛选的示例代码
2021/01/14 Vue.js
python Django模板的使用方法
2016/01/14 Python
python实现csv格式文件转为asc格式文件的方法
2018/03/23 Python
解决python爬虫中有中文的url问题
2018/05/11 Python
pytorch + visdom CNN处理自建图片数据集的方法
2018/06/04 Python
selenium+python自动化测试环境搭建步骤
2019/06/03 Python
远程部署工具Fabric详解(支持Python3)
2019/07/04 Python
python 实现字符串下标的输出功能
2020/02/13 Python
如何在Python对Excel进行读取
2020/06/04 Python
Pytorch 扩展Tensor维度、压缩Tensor维度的方法
2020/09/09 Python
python使用bs4爬取boss直聘静态页面
2020/10/10 Python
python使用requests库爬取拉勾网招聘信息的实现
2020/11/20 Python
HTML5去掉输入框type为number时的上下箭头的实现方法
2020/01/03 HTML / CSS
伦敦高级内衣品牌:Agent Provocateur(大内密探)
2016/08/23 全球购物
UNIX命令速查表
2012/03/10 面试题
党员岗位承诺书
2014/03/25 职场文书
镇政府副镇长群众路线专题民主生活会对照检查材料
2014/09/19 职场文书
五年级学生期末评语
2014/12/26 职场文书