重现Ajax跨域问题
做两个简单的小项目,重现Ajax跨域的问题。后端语言使用Java
第一个是简单的订单系统,它访问/loadOrderList,最后返回json字符串中设置的订单。该项目使用Tomcat在端口7070上发布。
@ request mapping('/load Order list ')@响应体公共列表order load order list(字符串uid){//模拟订单数据Order O1=new Order();O1 . setid(' 111 ');O1 . settotal(333.33);O1 . setdate(' 2019-4-29 ');订单o2=新订单();O2 . setid(' 222 ');O2 . settotal(444.44);O2 . setdate(' 2019-5-29 ');订单o3=新订单();O3 . setid(' 333 ');O3 . settotal(555.55);O3 . setdate(' 2019-6-29 ');list order list=new ArrayList();list . add(O1);list . add(O2);list . add(O3);退货清单;}在另一个项目中,向订单系统发送ajax请求以获取订单集。这个项目是使用Tomcat插件在端口9090上发布的。
//index . JSP % @ page content type=' text/html;charset=UTF-8 ' language=' Java ' % html head title title/title script type=' text/JavaScript ' src=' http :https://code . jquery.com/jquery-1 . 11 . 3 . js '/script script type=' text/JavaScript ' function sendAjax(){ $。post(' http://localhost :7070/order/loadorderist ',' uid=1234 ',函数(数据){ alert(数据);});}/script/head body a href=' JavaScript : sendajax()' rel=' external nofollow ' rel=' external nofollow ' sendajax/a/body/html单击sendajax超链接向订单系统发送ajax请求。
通过开发人员工具发现,虽然服务器以状态代码200响应,但控制台报告了一个错误。
这是Ajax跨域错误的一种表现,原因分析如下。
Ajax跨域介绍
Ajax跨域问题是浏览器的同源策略造成的。首先要理解源头的概念。我们可以通过协议域名端口来确定来源。在上面的示例中,您可以将项目理解为源代码。Ajax请求可以启动对源中资源的访问,但是不同源之间的Ajax会导致问题。当对不同来源的资源发起Ajax请求时,浏览器会添加Origin字段来标识来源accept : */* accept-encoding : gzip,deflate,br accept-language: zh-cn,zh;q=0.9 connection : keep-aliveContent-length : 8 content-type : application/x-www-form-URL encoded;charset=utf-8 host : localhost :7070 Origin : http://localhost 33609090协议域名端口服务器将根据Origin字段决定是否批准此请求。如果源指定的源不在允许的范围内,服务器将返回一个没有访问控制-允许-源字段的响应。当浏览器发现此字段丢失时,它将报告一个错误。这个错误不能通过状态代码来识别,因为状态代码可能是200(见上面的例子)。Ajax跨域解决方案
下面描述了最常用的Ajax跨域解决方案。
1.在服务器上添加响应头访问控制允许来源
既然我们已经知道了埃阿斯跨域失败是因为响应中缺少了响应头访问控制允许来源,那么就想办法加上去。以爪哇项目为例,在后端我们使用CORSFilter过滤器加上该响应头。(假设是专家项目), 首先在pom.xml中添加坐标依赖项groupIdcom.thetransactioncompany/groupId艺术公司-筛选器/artifactId版本2.5/版本scoperuntime/范围/依赖项然后在web.xml中对过滤器进行配置过滤器过滤器名称CORS/过滤器名称过滤器类别com。tratransactioncompany。CORS。CORS滤波器/滤波器级初始化参数param-namecors.allowOrigin/param-name!-这个标签是关键, *代表所有源都能访问-参数值*/参数值/初始化参数初始化参数param-namecors.supportedMethods/param-name参数-值获取、开机自检、磁头、放入、删除/参数值/初始化参数初始化参数param-namecors.supportedHeaders/param-name参数-值接受、来源、X-请求-伴随、内容-类型、上次修改/参数值/初始化参数初始化参数param-namecors.exposedHeaders/param-name参数-值集-Cookie/param-value/init-param init-param param-namecors.supportsCredentials/param-name参数-值true/参数-值/初始化-参数/初始化-参数/过滤器-过滤器配置后重启订单项目,再次发起埃阿斯请求可以看到成功返回数据,响应头中包含了访问控制允许来源,值为发起埃阿斯请求的源。
二。使用JSONP解决
上面直接通过过滤器添加响应头的方法可以说是对症下药,那么还有没有什么偏方呢?还真的有。在jsp文件中经常通过通过脚本标签引入一段射流研究…代码,这段代码通常来源于网络,也就是不同源。那么我们不妨通过srcipt标签完成埃阿斯请求,这样便顺带解决了跨域问题。下面还是沿用上面的案例进行演示。我们对发送创建交互式、快速动态网页应用的网页开发技术的jsp进行修改“% @”页面内容类型=' text/html;字符集=UTF-8 '语言=' Java ' % html标题标题/标题脚本类型=' text/JavaScript ' src=' http :https://代码。jquery。com/jquery-1。11 .3 .js /脚本函数doCallBack(数据){ var str=JSON.stringify(数据);警报;}/script/head body script src=' http :http://localhost :7070/order/LoadOrderList 3?uid=111回调=doCallBack '/脚本/正文/html上面的代码中,我们首先定义了doCallBack()函数,它接收一个字符串参数,并且会把接收到的字符串显示出来。然后在身体标签中编写脚本标签,我们将通过脚本标签请求订单系统,订单系统将会返回一段射流研究…代码,这段射流研究…代码会调用doCallBack()方法。为了能够拼接出doCallBack(字符串参数.)js代码,我们在订单系统中作如下操作@ request mapping('/LoadOrderList 3 ')@ responseBodyPublic String LoadOrderList 3(字符串uid,字符串回调){ //模拟订单数据订单o1=新订单();O1。setid(' 111 ');O1。settotal(333.33);O1。setdate(' 2019-4-29 ');订单o2=新订单();O2。setid(' 222 ');O2。settotal(444.44);O2。setdate(' 2019-5-29 ');订单o3=新订单();O3。setid(' 333 ');O3。settotal(555.55);O3。setdate(' 2019-6-29 ');列表顺序列表=new ArrayList();名单。添加(O1);名单。添加(O2);名单。添加(O3);//拼接射流研究…代码字符串结果=回调(' JSON。tojsonString(list)“)”;返回结果;}这个想法是不是很妙?明白这个原理之后,我们可以使用框架方便进行JSONP操作,在上面的代码中我们人为指定了一个名为doCallBack的函数,而框架会随机用时间戳生成一个函数名,原理和上面是一样的。
所以完成一开时点击超链接发送埃阿斯请求只需要如下几步。
“%@”页面内容类型=' text/html;charset=UTF-8 ' language=' Java ' % html head title title/title script type=' text/JavaScript ' src=' http :https://code . jquery.com/jquery-1 . 11 . 3 . js '/script script function sendAjax(){ $。getJSON(' http://localhost :7070/order/loadorderist 3?回调=?”,' uid=111 ',函数(数据){ var str=JSON.stringify(数据);警报;});}/script/head body a href=' JavaScript : sendajax()' sendajax/a/body/html摘要
以上两种解决方案在思维上有本质区别。第一种解决方案抓住了CORS跨域访问问题的本质,增加了一个响应头来解决跨域问题。第二个解决方案JSONP使用了脚本标签可以跨域获取js代码的特性,绕过了跨域问题。
摘要
以上就是本文的全部内容。希望本文的内容对大家的学习或工作有一定的参考价值。谢谢你的支持。