国内最全IT社区平台 联系我们 | 收藏本站
华晨云阿里云优惠2
您当前位置:首页 > web前端 > htmlcss > Jsonp解决ajax跨域问题

Jsonp解决ajax跨域问题

来源:程序员人生   发布时间:2016-06-03 18:54:41 阅读次数:4732次

1、介绍

最近跨域问题比较多,而且自己恰好也看到这1块,就总结了1下,关于JSONP的东西百度的话东西确切很多,很多人都是复制他人的,如此下去,其实找的资料就那末几份,关键是我还看不懂,多是能力问题吧,自己经过很多尝试,所以总结了1下,终究还是弄懂了皮毛。注意1点是,这里是用Jsonp解决ajax的跨域问题,具体的实现其实不是ajax

1、同源策略

阅读器有1个很重要的概念——同源策略(Same-Origin Policy)。所谓同源是指,域名,协议,端口相同。不同源的客户端脚本(javascript、ActionScript)在没明确授权的情况下,不能读写对方的资源。

2、JSONP

JSONP(JSON with Padding)是JSON的1种”使用模式”,可用于解决主流阅读器的跨域数据访问的问题。由于同源策略,1般来讲位于 server1.example.com 的网页没法与不是 server1.example.com的服务器沟通,而 HTML 的script 元素是1个例外。利用 <script> 元素的这个开放策略,网页可以得到从其他来源动态产生的 JSON 资料,而这类使用模式就是所谓的 JSONP。用 JSONP 抓到的资料其实不是 JSON,而是任意的JavaScript,用 JavaScript 直译器履行而不是用 JSON 解析器解析。

2、实践

1、摹拟跨域要求

在本机弄两个tomcat,端口分别为8080,8888,也就满足了非同源的条件,那末要是从1个端口发送ajax去获得另外1个端口的数据,那末肯定会报跨域要求问题。

这里写图片描述

这里有两个项目,分别是jsonp(8080),other(8888),在jsonp项目中index.jsp以下:

<%@ page language="java" contentType="text/html; charset=UTF⑻" pageEncoding="UTF⑻"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>Insert title here</title> <script type="text/javascript" src="js/jquery.min.js"></script> <script type="text/javascript"> function jsonp_fun(){ $.ajax({ url:'http://localhost:8888/other/index.jsp', type:'post', dataType:'text', success:function(data){ console.log(data); } }); } </script> </head> <body> <input type="button" value="jsonp" onclick="jsonp_fun()"/> </body> </html>

other(8888)项目中index.jsp以下:// 由于jsp实际就是servlet,这里就用jsp代替servlet演示。

<%@ page language="java" contentType="text/html; charset=UTF⑻" pageEncoding="UTF⑻"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>Insert title here</title> <script type="text/javascript" src="js/jquery.min.js"></script> </head> <body> other domain </body> </html>

其实中上面看不过就是jsonp页面中点击按钮ajax去获得other页面中的数据。

结果以下:chrome控制台

这里写图片描述

XMLHttpRequest cannot load http://localhost:8888/other/index.jsp. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8080' is therefore not allowed access.

以上提示就是指跨域问题,不能从8080这个域去访问8888域的资源。

2、利用script标签去访问other域的js文件

由于<script>标签的src是支持跨域要求的。最多见的就是CDN服务的利用啦,比如我项目中,如果想用jquery,但是就没有这个js文件,去下载要找很久,而且版本还不知道下的对不对,那末可以百度搜jquery cdn,我随意找1个,比如bootstrap的cdn:http://www.bootcdn.cn/jquery/,有很多版本供你选择,只要在项目中加上就好了,最大缺点的话就是你没网的话,就引入不到啦。

  • 2.1 在other根路径创建js/other.js文件,内容以下:
alert("this is other(8888) js");
  • 2.2 在jsonp/index.jsp中,加入script标签,引入other的js
<script type="text/javascript" src="http://localhost:8888/other/js/other.js"></script>

进入http://localhost:8080/jsonp/index.jsp,会立马弹出alert,表示引入的js文件自动履行了,跨域要求js成功。

这里写图片描述

  • 2.3 一样的,直接援用,会立马履行立马的alert,那末在other.js中写函数,一样jsonp/index.jsp中也能调用到,这点就不演示了,项目开发中大多都是这样做的,页面与js/css分离。

  • 2.4 另外说明1点,如果在other.js中有函数通过ajax调用8080中的东西,然后引入以后,调用这个函数,也是可以的,但是如果other.js中函数ajax调用8888的东西,引入以后,调用这个函数,一样是跨域的。

3、script实现跨域要求

将jsonp/index.jsp改成以下:这里注意引入的other.js的位置,是在函数getResult以后的,如果在它之前的话,会提示函数不存在。js加载顺序是从上开始,在之前调用没创建的,不能成功。注意这里是指引入的js文件,如果是同1个js文件或当前页面的js中,先履行调用,然后再写函数也是没有问题的,但是如果先履行调用引入js文件中的函数,然后再引入js文件,就会提示函数不存在。

<script type="text/javascript" src="js/jquery.min.js"></script> <script type="text/javascript"> function jsonp_fun(){ $.ajax({ url:'http://localhost:8888/other/index.jsp', type:'post', dataType:'text', success:function(data){ console.log(data); } }); } function getResult(data){ alert(data.result); } </script> <script type="text/javascript" src="http://localhost:8888/other/js/other.js"></script>

然后other.js

getResult({"result":"this is other domain's data"});

也就是在jsonp/index.jsp页面写好函数,然后引入其他域的js传入参数去调用这个函数,这里的参数你可以先看作是其他域服务器的接口返回的数据。

刷新页面,效果固然是

弹出alert框,this is other domain's data
  • 3.2 摹拟接口访问
    看到这里,你会不会还是想不懂,上面js弄啥的,传个死的数据,有甚么实际意义吗?,其实script的src不但可以接js的地址,还可以接servlet的地址,也就是http接口地址,所以接下来,懒得写servlet,这里还是写jsp当作接口,在other项目中新建other.jsp页面,内容以下:
<%@ page language="java" contentType="text/html; charset=UTF⑻" pageEncoding="UTF⑻"%> <% String params = request.getParameter("params"); out.println("ajax cross success,the server receive params :"+params); %>

内容很简单,也就是接受1个params的参数,然后返回数据给调用者。

我们在jsonp/index.jsp中加上

<script type="text/javascript" src="http://localhost:8888/other/other.jsp?params=fromjsonp"></script>

看到这个地址,你是否是很熟习,不熟习的证明你用servlet用蠢了,jsp也是servlet,流程就是页面1加载的时候,script标签就会去发送要求,然后返回数据。那末我们刷新页面,看看效果。

这里写图片描述

Uncaught SyntaxError: Unexpected identifier

报错了,如上,然后代码有问题?No,点击毛病,你会看到要求的东西也打印出来了,就是提示毛病,表示这个东西阅读器不认识,实际上是script不认识啦。

这里写图片描述

还不明白,那末你去页面加上以下内容,你看报不报错!!肯定报错

<script type="text/javascript"> ajax cross success,the server receive params : jsonp_param </script>

那末js不能解析,我们换1种思路,要是我们输出的是JSON字符串或调用当前页面函数的字符串了,类似于3.1中返回的
getResult({“result”:”this is other domain’s data”});

所以改造1下,把other.jsp中的内容改成

<%@ page language="java" contentType="text/html; charset=UTF⑻" pageEncoding="UTF⑻"%> <% String params = request.getParameter("params"); //out.println("ajax cross success,the server receive params :"+params); out.println("getResult({'result':'"+params+"'})"); %>

别忘了,之前jsonp/index.jsp中我们定义了,那末加入援用以后,仍然记得getResult函数与引入函数的前后顺序问题。

<script type="text/javascript"> function getResult(data){ alert(data.result); } </script> <script type="text/javascript" src="http://www.wfuyu.com/upload/caiji/20160601/http://localhost:8888/other/other.jsp?params=fromjsonp"></script>

刷新页面,发现大工告成。

这里写图片描述

至此,大部份原理已讲完了,还有1个问题,这里服务器返回的是getResult(xxx),其中这里的xxx可以当作是经过接口的很多处理,然后塞进去的值,但是这个getResult这个函数名,调用方与其他域服务器这1方怎样约定这个名字是1致的了,况且很多公司自己做服务的,别的公司的开发人员去调用,难道每一个人都去那末公司去约定调用函数的名字?怎样可能,所以有人就想出来了1种解决方案,固然不是我~~,其实也很简单啦,也就是把回调的函数名字也1起传过去不就好了,所以代码以下:

<script type="text/javascript" src="http://localhost:8888/other/other.jsp?params=fromjsonp&callback=getResult"></script>

other.jsp

<%@ page language="java" contentType="text/html; charset=UTF⑻" pageEncoding="UTF⑻"%> <% String params = request.getParameter("params"); String callback = request.getParameter("callback"); // 经过该接口1系列操作,然后得到data,将data返回给调用者 String data = "{'result':'"+params+"'}"; out.println(callback + "("+data+")"); %>

代码很简单,也就是传递1个回调函数的参数名,然后经过该接口1系列操作,将返回数据,塞到回调函数里面,调用真个函数就得到了该接口的数据,也就是类似于ajax中succsss:function(data),然后处理data1样,这里的success回调函数,相当于上面的getResult函数。固然你也能够写的优雅1点,比如:

function CreateScript(src) { $("<script><//script>").attr("src", src).appendTo("body") } function jsonp_fun(){ CreateScript("http://localhost:8888/other/other.jsp?params=fromjsonp&callback=getResult") }

4、Jquery的JSONP

至此跨域要求的原理已讲清楚了,但是依然还有1个问题,总觉得这样用有点怪是否是,如果用jquery的话,调用就很简单了,其实jquery底层实现也是拼了1个script,然后指定src这类方式,跟上面讲的1样,只是jquery封装了1下,显得更加优雅,跟ajax调用方式差不多,所以容易记,代码以下:

<script type="text/javascript"> function getResult(data){ alert("through jsonp,receive data from other domain : "+data.result); } function jsonp_fun(){ $.ajax({ url:'http://localhost:8888/other/other.jsp', type:'post', data:{'params':'fromjsonp'}, dataType: "jsonp", jsonp: "callback",//传递给要求处理程序或页面的,用以取得jsonp回调函数名的参数名(1般默许为:callback) jsonpCallback:"getResult",//自定义的jsonp回调函数名称,默许为jQuery自动生成的随机函数名,也能够不写这个参数,jQuery会自动为你处理数据 success: function(data){ }, error: function(){ alert('fail'); } }); } </script> <body> <input type="button" value="jsonp" onclick="jsonp_fun()"/> </body>

这里的jsonCallback,回调函数设置为getResult,那末返回后会先调用getResult函数中的代码,再调用success函数中的代码,1般情况下,不用定义getResult函数,一样jsonCallback不需要设置,那末就只履行success中的代码,也就跟平时的ajax1样用啦。

所以实际工作用法以下:

function jsonp_fun(){ $.ajax({ url:'http://localhost:8888/other/other.jsp', type:'post', data:{'params':'fromjsonp'}, dataType: "jsonp", jsonp: "callback",//传递给要求处理程序或页面的,用以取得jsonp回调函数名的参数名(1般默许为:callback) success: function(data){ alert("through jsonp,receive data from other domain : "+data.result); }, error: function(){ alert('fail'); } }); }
<%@ page language="java" contentType="text/html; charset=UTF⑻" pageEncoding="UTF⑻"%> <% String params = request.getParameter("params"); String callback = request.getParameter("callback"); // 经过该接口1系列操作,然后得到data,将data返回给调用者 String data = "{\"result\":\""+params+"\"}"; out.println(callback + "("+data+")"); %>

这里没有指定jsonpCallback,实际上jquery底层拼装了1个函数名,固然生成函数规则就没研究了。

这里写图片描述

补充:

  • 1、ajax和jsonp这两种技术在调用方式上“看起来”很像,目的也1样,都是要求1个url,然后把服务器返回的数据进行处理,因此jquery和ext等框架都把jsonp作为ajax的1种情势进行了封装;

  • 2、但ajax和jsonp其实本质上是不同的东西。ajax的核心是通过XmlHttpRequest获得非本页内容,而jsonp的核心则是动态添加<script>标签来调用服务器提供的js脚本。

  • 3、所以说,其实ajax与jsonp的区分不在因而否跨域,ajax通过服务端代理1样可以实现跨域,jsonp本身也不排挤同域的数据的获得。

  • 4、还有就是,jsonp是1种方式或说非强迫性协议,犹如ajax1样,它也不1定非要用json格式来传递数据,如果你愿意,字符串都行,只不过这样不利于用jsonp提供公然服务。

另外补充最后1点:

Jsonp能解决的ajax跨域要求其实相当有限,推荐还是使用CROS,由于Jsonp的要求只能是get,虽然在上面演示中,我设置的type为post,但是实际上发的要求还是get,所以也就造成了万1我的要求是post了,怎样办,要是跨域ajax文件上传了,怎样办,这点希望大家注意:

这里写图片描述

生活不易,码农辛苦
如果您觉得本网站对您的学习有所帮助,可以手机扫描二维码进行捐赠
程序员人生
------分隔线----------------------------
分享到:
------分隔线----------------------------
关闭
程序员人生