深入分析Jsonp解决ajax跨域问题
一.导言
最近有很多跨领域的问题,刚看到这一块,就总结了一下。百度有很多关于JSONP的东西,很多人都在抄袭别人。如果这种情况继续下去,实际上只有几份我正在寻找的信息。关键是我还是看不懂。也许是能力的问题。我尝试了很多,所以总结之后,终于明白了皮毛。需要注意的一点是,Jsonp是用来解决ajax的跨域问题的,但具体实现并不是ajax。
1、同源策略。
浏览器中有一个非常重要的概念:——同源策略。同源是指相同的域名、协议和端口。来自不同来源的客户端脚本(JavaScript和ActionScript)在没有明确授权的情况下无法读写彼此的资源。
2、JSONP
JSONP(带Padding的JSON)是JSON的一种“使用模式”,可以用来解决主流浏览器的跨域数据访问问题。一般来说,由于同源策略,除了HTML脚本元素,位于server1.example.com的网页无法与server1.example.com以外的服务器进行通信。有了脚本元素的这种开放策略,网页就可以获得其他来源动态生成的JSON数据,这种使用模式叫做JSONP。JSONP捕获的数据不是JSON,而是任意的JavaScript,由JavaScript文字翻译器执行,而不是JSON解析器。
第二,练习。
1.模拟跨域请求。
在这台机器上得到两个tomcat,端口分别是8080和8888,满足非同源条件。如果从一个端口发送ajax来获取另一个端口的数据,肯定会报告跨域请求的问题。
这里有两个项目,分别是jsonp(8080)和其他(8888),jsonp项目中的index.jsp如下:
% @ page language=' Java ' ContentType=' text/html;charset=UTF-8 ' page encoding=' UTF-8 ' %!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.01 Transitional//EN ' ' http://www . w3 . org/TR/HTML 4/loose . DTD ' HTML head title在此插入标题/title script type=' text/JavaScript ' src=' http : js/jquery . min . js '/script script type=' text/JavaScript ' function JSON p _ fun(){ $。Ajax({ URL : ' http://localhost :8888/other/index . JSP ',type:'post ',dataType:'text ',success:function(数据){console.log(数据);}});}/script/head dyinput 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-8 ' page encoding=' UTF-8 ' %!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.01 Transitional//EN ' ' http://www . w3 . org/TR/HTML 4/loose . DTD ' HTML head title insert title here/Script type=' text/JavaScript ' src=' http : js/jquery . min . js '/Script/head dyother domain/body/HTML其实上面的视图无非就是点击jsonp页面中的ajax按钮来获取其他页面中的数据。
结果如下:chrome控制台。
XMLHttpRequest无法加载http://localhost :8888/other/index.jsp。请求的资源上不存在“访问控制-允许-来源”标头。因此,不允许访问Origin 'http://localhost:8080 '。
以上提示涉及跨域问题,8888域的资源无法从8080域访问。
2.使用脚本标签访问其他域中的js文件。
因为脚本标记的src支持跨域请求。最常见的是CDN服务的应用。比如在我的项目中,如果你想用jQuery,但是你没有这个js文件,下载需要很长时间,而且不知道版本是否正确,可以通过百度搜索jquery cdn。我可以随便找一个,比如bootstrap的CDN:http://www.bootcdn.cn/jquery/.有很多版本供你选择。只需将它们添加到项目中。最大的缺点就是如果没有关系网,就不能介绍他们。
2.1在另一个根路径中创建一个js/other.js文件,内容如下:
alert('这是other(8888)js ');2.2在jsonp/index.jsp中,添加脚本标签,引入其他的js。
脚本类型=' text/JAVAScript ' src=' http :3358 localhost 3360888/other/js/other . js '/脚本进入http://localhost :8080/jsonp/index . JSP,会立即弹出警报,表示导入的js文件自动执行,跨域请求js成功。
2.3同样,直接引用会立即执行alert,所以用other.js编写的函数也可以在jsonp/index.jsp中调用,不做演示。这主要是在项目开发中完成的,页面是从js/css中分离出来的。
2.4另外一点,如果other.js中有一个函数通过ajax调用8080中的某个东西,然后引入后调用这个函数,也是可以的,但是如果other.js中的函数ajax引入后调用8888中的某个东西,也是跨域的。
3.脚本实现跨域请求。
3.1简单模拟服务器返回的数据。
将jsonp/index.jsp更改如下:注意这里介绍的other.js的位置在函数getResult之后。如果在它之前,它会提示函数不存在。js的加载顺序从顶部开始,调用之前没有创建,所以不可能成功。请注意,这是指导入的js文件。如果是同一个js文件或者是当前页面的js,先执行调用再写函数是没有问题的。但是如果先执行引入js文件的函数,再引入js文件,会提示函数不存在。
script type=' text/JavaScript ' src=' http : 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(数据){console.log(数据);}});}函数GetResult(data){ alert(data . result);}/script script type=' text/JAVAScript ' src=' http :3358 localhost 33608888/other/js/other.js '/script然后是other . js。
getResult({'result': '这是其他域的数据' });
也就是说,在jsonp/index.jsp页面上编写函数,然后引入其他域的js传入参数来调用这个函数。这里的参数可以看作是其他域服务器接口返回的数据。
刷新页面,效果当然是。
弹出提示框,这是其他域的数据。
3.2模拟接口访问。
看到这里,你会不会还不明白,上面的js在做什么,传递一个死数据有什么实际意义?其实脚本的src不仅可以拾取js的地址,还可以拾取servlet的地址,也就是http接口的地址,所以接下来,我懒得写servlet了,但我还是在这里写jsp作为接口,在其他项目中创建新的other页面,内容如下:
% @ page language=' Java ' ContentType=' text/html;charset=UTF-8 ' page encoding=' UTF-8 ' % % String params=request . getparameter(' params ');out.println('ajax交叉成功,服务器接收params : ' params);% content非常简单,即接受一个params参数,然后将数据返回给调用者。
我们添加了jsonp/index.jsp。
脚本类型=' text/JavaScript ' src=' http :http://localhost :8888/other/other . JSP?params=fromjsonp '/脚本看到这个地址,你熟悉吗?不熟悉证明你用servlet很蠢。jsp也是一个servlet。这个过程是,一旦页面被加载,脚本标签将发送一个请求,然后返回数据。然后让我们刷新页面,看看效果。
未捕获的语法分析器:意外标识符
错误,如上,然后代码有问题?不,如果你点击错了,你会看到请求的东西也被打印出来,这意味着浏览器不知道这个东西,但实际上脚本不知道。
我还不明白,你去页面添加以下内容,就可以看报纸不报错了!必须报告错误。
脚本类型=' text/JavaScript' Ajax交叉成功,服务器接收到params 3360 jsONP _ param/脚本,所以JS无法解析。我们换个思路,如果输出JSON字符串或者调用当前页面函数的字符串,是不是和3.1中返回的getresult类似({“result”:“这是其他域的数据”});
所以修改一下,把other.jsp的内容改成。
% @ page language=' Java ' ContentType=' text/html;charset=UTF-8 ' page encoding=' UTF-8 ' % % String params=request . getparameter(' params ');//out.println('ajax交叉成功,服务器接收params : ' params);out . println(' GetResult({ ' result ' : ' ' params ' ' })');%别忘了,之前我们在jsonp/index.jsp中定义过,所以添加引用后,我们还记得getResult函数和导入函数的顺序。
脚本类型='text/javascript '函数getResult(data){ alert(data . result);}/script script type=' text/JavaScript ' src=' http :3358 localhost :8888/other/other . JSP?params=fromjsonp '/脚本刷新页面,发现伟大的工作已经完成。
至此,大部分原则都已经完成了,还有一个问题。这里,服务器返回getResult(xxx),其中xxx可以看作是一个值,由很多接口处理后再填充进去。但是,函数名getResult与调用者和其他域服务器对该名称的约定是一致的。此外,许多公司提供自己的服务,其他公司的开发者称之为服务。每个人都去那家公司约定呼叫功能的名称吗?怎么样,所以有人想出了一个解决办法,当然不是我~ ~,但其实很简单,就是把回调函数名一起传是不够的,所以代码如下:
脚本类型=' text/JavaScript ' src=' http :http://localhost :8888/other/other . JSP?params=fromjsoncallback=GetResult '/script other . JSP
% @ page language=' Java ' ContentType=' text/html;charset=UTF-8 ' page encoding=' UTF-8 ' % % String params=request . getparameter(' params ');字符串回调=request.getParameter('回调');//在这个接口上进行一系列操作之后,我们得到数据并返回给调用者字符串data=' { ' result ' : ' ' params ' ' } ';out.println(回调'(' data ')');%代码非常简单,就是传递一个回调函数的参数名,然后在接口上进行一系列操作后,将返回的数据填充到回调函数中。调用端的函数获取接口的数据,类似于ajax中的success:function(data),然后处理数据。这里的成功回调函数相当于上面的getResult函数。当然,你也可以写得优雅,比如:
函数create script(src){ $(' script//script ')。attr('src ',src)。appendo(' body ')函数jsonp _ fun(){ create script(' http://localhost :8888/other/other . JSP?params=fromjsoncallback=get result ')} 4。Jquery的jsonp。
至此,跨域请求的原则已经明确,但仍存在问题。总觉得用起来有点奇怪。如果使用jquery,调用非常简单。事实上,jquery的底层实现也拼写了一个脚本,然后指定了src。和上面一样,只是被jquery封装了,更优雅,类似于ajax调用,所以很容易记住。代码如下:
脚本类型='text/javascript '函数getResult(data){alert('通过jsonp,从其他域接收数据: ' data . result);}函数jsonp_fun(){$。Ajax({ URL : ' http://localhost :8888/other/other . JSP ',type:'post ',data : { ' params ' : ' from jsonp ' },Type:' jsonp ',jsonp:' callback ',//传递给请求处理程序或页面以获取jsonp回调函数名称的参数名称(通常默认为: callback),jsonpjQuery会自动为您处理数据成功:函数(数据){},错误:函数(){ alert(' fail ');}});}/script body input type=' button ' value=' jsonp ' onclick=' jsonp _ fun()'//body在这里,jsonCallback,将回调函数设置为getResult,那么首先调用getResult函数中的代码,然后调用success函数中的代码。一般不需要定义getResult函数,也不需要设置jsonCallback,只需要成功执行代码就可以了,就像平时的ajax一样。
因此,实际工作用途如下:
函数jsonp_fun(){$。Ajax({ URL : ' http://localhost :8888/other/other . JSP ',type:'post ',data : { ' params ' : ' from jsonp ' },Type:' jsonp ',jsonp:' callback ',//参数名传递给请求处理程序或页面以获取jsonp回调函数名(一般默认为: callback)成功3360函数(},error : function(){ alert(' fail ');}});} % @ page language=' Java ' ContentType=' text/html;charset=UTF-8 ' page encoding=' UTF-8 ' % % String params=request . getparameter(' params ');字符串回调=request.getParameter('回调');//在这个接口上进行一系列操作之后,我们得到数据并返回给调用者字符串data=' { \ ' result ' : \ ' ' params ' \ ' } ';out.println(回调'(' data ')');%此处没有指定jsonpCallback。事实上,函数名是在jquery的底部组装的,但是当然,生成函数的规则还没有被研究过。
补充:
1.ajax和jsonp在调用方法上是“相似”的,并且有着相同的目的。它们都请求一个url,然后处理服务器返回的数据。因此,jquery和ext都将jsonp封装为ajax的一种形式。
2.但是ajax和jsonp本质上是不同的东西。ajax的核心是通过XmlHttpRequest获取非页面内容,而jsonp的核心是动态添加脚本标签来调用服务器提供的js脚本。
3.所以,事实上,ajax和jsonp的区别不在于它是否跨域。ajax可以跨域,jsonp本身也不排除获取同一个域中的数据。
4.此外,jsonp是一种模式或非强制协议。像ajax一样,它不必使用json格式来传输数据。如果你愿意,字符串就可以,但是这不利于用jsonp提供公共服务。
以上内容是边肖介绍的关于Jsonp解决ajax跨域问题的相关信息,希望对大家有所帮助!
版权声明:深入分析Jsonp解决ajax跨域问题是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。