深入浅出jsonp
前言
第一次听说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请求没有跨域,完美得到结果:
但是如果我的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就要出马了!
神奇的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数据,但是报错如下:
原因是因为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 });
当然,这时的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.')'; ?>
当然类似的封装好的方法还有几种:
$.getJSON("http://localhost:8080/test.php?callback=?", function(data) { console.log(data); }); $.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名的话,可以参照上文。
总结
由于同源策略的限制,XmlHttpRequest只允许请求当前源(域名、协议、端口)的资源,为了实现跨域请求,可以通过script标签实现跨域请求,然后在服务端输出JSON数据并执行回调函数,从而解决了跨域的数据请求,这就是jsonp的核心。
jsonp原理:
- 首先在客户端注册一个callback, 然后把callback的名字传给服务器。
- 服务器先生成 json 数据。 然后以 javascript 语法的方式,生成一个function , function 名字就是传递上来的参数 jsonp. 最后将 json 数据直接以入参的方式,放置到 function 中,这样就生成了一段 js 语法的文档,返回给客户端。
- 客户端浏览器,解析script标签,并执行返回的 javascript 文档,此时数据作为参数,传入到了客户端预先定义好的 callback 函数里.(动态执行回调函数)
深入浅出jsonp的更多相关文章
- 深入浅出jsonp(转)
前言 第一次听说jsonp,其实早在2年之前.当时在做一个活动页面的抽奖模块,要从服务端get一个概率,当时什么都不懂,同事说用ajax,我就用ajax,同事说dataType改成jsonp,我就改成 ...
- JS同源策略和跨域问题
同源策略和跨域问题:http://www.cnblogs.com/chaoyuehedy/p/5556557.html 深入浅出JSONP--解决ajax跨域问题:http://www.cnblogs ...
- XSS中的同源策略和跨域问题
转自 https://www.cnblogs.com/chaoyuehedy/p/5556557.html 1 同源策略 所谓同源策略,指的是浏览器对不同源的脚本或者文本的访问方式进行的限制.比如源a ...
- XSS中的同源和跨域的问题
学习自https://www.cnblogs.com/-qing-/p/10966047.html 也谈谈同源策略和跨域问题 1 同源策略 所谓同源策略,指的是浏览器对不同源的脚本或者文本的访问方式进 ...
- 深入浅出:了解jsonp跨域的九种方式
什么是“”跨域”: 跨域访问,简单来说就是 A 网站的 javascript 代码试图访问 B 网站,包括提交内容和获取内容.由于安全原因,跨域访问是被各大浏览器所默认禁止的.当一个域与其他域建立了信 ...
- JSONP的学习(收集整理)
JSONP和JSON之间有什么联系吗? JSON(JavaScript Object Notation) 是一种轻量级.可读的基于文本的的数据交换格式.,是一种轻量的数据交换开放标准.源于JavsSc ...
- 解决浏览器跨域限制方案之JSONP
一.什么是JSONP JSONP即:JSON with Padding,是一种解决因浏览器跨域限制不允许访问跨域资源的方法. JSONP是一个非官方的协议,它允许在服务器端返回javascript标签 ...
- 深入浅出的webpack构建工具---webpack基本配置(一)
深入浅出的webpack构建工具---webpack基本配置(一) 阅读目录 一:webpack入门构建: 1. 安装webpack到全局 2. 安装webpack到本项目. 3. 如何使用webpa ...
- Jsonp 关键字详解及json和jsonp的区别,ajax和jsonp的区别
为什么要用jsonp? 相信大家对跨域一定不陌生,对同源策略也同样熟悉.什么,你没听过?没关系,既然是深入浅出,那就从头说起. 假如我写了个index页面,页面里有个请求,请求的是一个json数据(不 ...
随机推荐
- SAM4E单片机之旅——14、LCD之SMC的配置
在上个例子中,已经在ASF添加了ILI93xx模块,并做好了相关的声明.这次就做好SMC的配置,然后使用ASF提供的API在屏幕上打印出”Hello World!”字样. 一. 电路图 开发板的LCD ...
- linux 2>&1
2>&1就是用来将标准错误2重定向到标准输出1中的.此处1前面的&就是为了让bash将1解释成标准输出而不是文件1.至于最后一个&,则是让bash在后台执行 例如:/us ...
- MYSQL性能调优: 对聚簇索引和非聚簇索引的认识
聚簇索引是对磁盘上实际数据重新组织以按指定的一个或多个列的值排序的算法.特点是存储数据的顺序和索引顺序一致.一般情况下主键会默认创建聚簇索引,且一张表只允许存在一个聚簇索引. 在<数据库原理&g ...
- 关于Redis info的参数总结
Redis官网对 info 已经讲解的比较清楚的,参考文档 .可以看到,info的输出结果是分几块的,有Servers.Clients.Memory等等,通过info后面接这些参数,可以指定输出某一块 ...
- Apache2.4和Apache2.2访问控制配置语法对比
一.访问控制 在Apache2.2版本中,访问控制是基于客户端的主机名.IP地址以及客户端请求中的其他特征,使用Order(排序), Allow(允许), Deny(拒绝),Satisfy(满足)指令 ...
- inux下文件权限设置中的数字表示权限,比如777,677等,这个根据什么得来的
chmod ABC file 其中A.B.C各为一个数字,分别表示User.Group.及Other的权限. A.B.C这三个数字如果各自转换成由“0”.“1”组成的二进制数,则二进制数的每一位分别代 ...
- 基于jython操作hbase
一.前言 关于jython介绍,直接上官网www.jython.org,可以得到详细资料,这里只介绍一下jython操作hbase的一些方法,本质上和用java操作hbase差不多,只不过语法换成了p ...
- Android分步注册,Activity由B返回A修改再前往B,B中已填项不变
某日突然想到标题问题,一般来说返回上一个Activity,当前Activity应该自动销毁.要想保留值,便想到用bundle传递的方式 最后功能是实现了,但感觉方法很笨. 主要代码如下: packag ...
- 使用jmx监控tomcat
1.在tomcat启动过程中,开启相应的参数配置: -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9999 -D ...
- hihocoder 1388 &&2016 ACM/ICPC Asia Regional Beijing Online Periodic Signal
#1388 : Periodic Signal 时间限制:5000ms 单点时限:5000ms 内存限制:256MB 描述 Profess X is an expert in signal proce ...