复现Ajax跨域问题
做两个简单的小项目复现Ajax跨域问题. 后端语言使用Java
首先是一个简单的订单系统, 通过访问/loadOrderList, 最终以json串形式返回订单集合. 该项目使用Tomcat发布在7070端口.
@RequestMapping("/loadOrderList") @ResponseBody public List<Order> loadOrderList(String uid){ //模拟订单数据 Order o1 = new Order(); o1.setId("111"); o1.setTotal(333.33); o1.setDate("2019-4-29"); Order o2 = new Order(); o2.setId("222"); o2.setTotal(444.44); o2.setDate("2019-5-29"); Order o3 = new Order(); 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); return list; }
在另一个项目中做一个向订单系统发送一个ajax请求, 获取订单集合. 该项目使用Tomcat插件发布在9090端口.
//index.jsp <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> <script type="text/javascript" src="/UploadFiles/2021-04-02/jquery-1.11.3.js">点击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-alive Content-Length: 8 Content-Type: application/x-www-form-urlencoded; charset=UTF-8 Host: localhost:7070 Origin: http://localhost:9090 协议+域名+端口
- 服务器会根据Origin字段决定是否同意这次请求, 如果Origin指定的源不在许可范围内, 服务器会返回一个不带有Access-Control-Allow-Origin字段的响应. 浏览器解析时发现缺少了这个字段, 就会报错. 这种错误不能通过状态码识别, 因为状态码很有可能就是200(见上面的案例).
Ajax跨域解决方案
下面介绍最常用Ajax跨域解决方案.
一. 在服务端添加响应头Access-Control-Allow-Origin
- 既然我们已经知道了Ajax跨域失败是因为响应中缺少了响应头Access-Control-Allow-Origin, 那么就想办法加上去.
- 以Java项目为例, 在后端我们使用CORSFilter过滤器加上该响应头.
- (假设是Maven项目), 首先在pom.xml中添加坐标
<dependency> <groupId>com.thetransactioncompany</groupId> <artifactId>cors-filter</artifactId> <version>2.5</version> <scope>runtime</scope> </dependency>
- 然后在web.xml中对过滤器进行配置.
<filter> <filter-name>CORS</filter-name> <filter-class>com.thetransactioncompany.cors.CORSFilter</filter-class> <init-param> <param-name>cors.allowOrigin</param-name><!--这个标签是关键, *代表所有源都能访问--> <param-value>*</param-value> </init-param> <init-param> <param-name>cors.supportedMethods</param-name> <param-value>GET, POST, HEAD, PUT, DELETE</param-value> </init-param> <init-param> <param-name>cors.supportedHeaders</param-name> <param-value>Accept, Origin, X-Requested-With, Content-Type, Last-Modified</param-value> </init-param> <init-param> <param-name>cors.exposedHeaders</param-name> <param-value>Set-Cookie</param-value> </init-param> <init-param> <param-name>cors.supportsCredentials</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>CORS</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
配置后重启订单项目, 再次发起Ajax请求可以看到成功返回数据, 响应头中包含了Access-Control-Allow-Origin
, 值为发起Ajax请求的源.
二. 使用JSONP解决
- 上面直接通过过滤器添加响应头的方法可以说是对症下药, 那么还有没有什么偏方呢"htmlcode">
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> <script type="text/javascript" src="/UploadFiles/2021-04-02/jquery-1.11.3.js">
- 上面的代码中, 我们首先定义了doCallBack()函数, 它接收一个字符串参数, 并且会把接收到的字符串显示出来.
- 然后在<body>标签中编写<script>标签, 我们将通过<script>标签请求订单系统, 订单系统将会返回一段js代码, 这段js代码会调用doCallBack()方法.
- 为了能够拼接出
doCallBack(字符串参数...)
js代码, 我们在订单系统中作如下操作.
@RequestMapping("/loadOrderList3") @ResponseBody public String loadOrderList3(String uid, String callBack){ //模拟订单数据 Order o1 = new Order(); o1.setId("111"); o1.setTotal(333.33); o1.setDate("2019-4-29"); Order o2 = new Order(); o2.setId("222"); o2.setTotal(444.44); o2.setDate("2019-5-29"); Order o3 = new Order(); 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); //拼接js代码 String result = callBack + "(" + JSON.toJSONString(list) + ")"; return result; }
这个想法是不是很妙"htmlcode">
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> <script type="text/javascript" src="/UploadFiles/2021-04-02/jquery-1.11.3.js">
小结
上面两种解决办法在思路上有着本质的不同. 方案一抓住CORS跨域访问问题的本质, 在后端加上响应头解决跨域问题. 方案二JSONP利用的是<script>标签能够跨域获取js代码的特性, 绕过跨域问题.
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对的支持。
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
《魔兽世界》大逃杀!60人新游玩模式《强袭风暴》3月21日上线
暴雪近日发布了《魔兽世界》10.2.6 更新内容,新游玩模式《强袭风暴》即将于3月21 日在亚服上线,届时玩家将前往阿拉希高地展开一场 60 人大逃杀对战。
艾泽拉斯的冒险者已经征服了艾泽拉斯的大地及遥远的彼岸。他们在对抗世界上最致命的敌人时展现出过人的手腕,并且成功阻止终结宇宙等级的威胁。当他们在为即将于《魔兽世界》资料片《地心之战》中来袭的萨拉塔斯势力做战斗准备时,他们还需要在熟悉的阿拉希高地面对一个全新的敌人──那就是彼此。在《巨龙崛起》10.2.6 更新的《强袭风暴》中,玩家将会进入一个全新的海盗主题大逃杀式限时活动,其中包含极高的风险和史诗级的奖励。
《强袭风暴》不是普通的战场,作为一个独立于主游戏之外的活动,玩家可以用大逃杀的风格来体验《魔兽世界》,不分职业、不分装备(除了你在赛局中捡到的),光是技巧和战略的强弱之分就能决定出谁才是能坚持到最后的赢家。本次活动将会开放单人和双人模式,玩家在加入海盗主题的预赛大厅区域前,可以从强袭风暴角色画面新增好友。游玩游戏将可以累计名望轨迹,《巨龙崛起》和《魔兽世界:巫妖王之怒 经典版》的玩家都可以获得奖励。
更新日志
- 凤飞飞《我们的主题曲》飞跃制作[正版原抓WAV+CUE]
- 刘嘉亮《亮情歌2》[WAV+CUE][1G]
- 红馆40·谭咏麟《歌者恋歌浓情30年演唱会》3CD[低速原抓WAV+CUE][1.8G]
- 刘纬武《睡眠宝宝竖琴童谣 吉卜力工作室 白噪音安抚》[320K/MP3][193.25MB]
- 【轻音乐】曼托凡尼乐团《精选辑》2CD.1998[FLAC+CUE整轨]
- 邝美云《心中有爱》1989年香港DMIJP版1MTO东芝首版[WAV+CUE]
- 群星《情叹-发烧女声DSD》天籁女声发烧碟[WAV+CUE]
- 刘纬武《睡眠宝宝竖琴童谣 吉卜力工作室 白噪音安抚》[FLAC/分轨][748.03MB]
- 理想混蛋《Origin Sessions》[320K/MP3][37.47MB]
- 公馆青少年《我其实一点都不酷》[320K/MP3][78.78MB]
- 群星《情叹-发烧男声DSD》最值得珍藏的完美男声[WAV+CUE]
- 群星《国韵飘香·贵妃醉酒HQCD黑胶王》2CD[WAV]
- 卫兰《DAUGHTER》【低速原抓WAV+CUE】
- 公馆青少年《我其实一点都不酷》[FLAC/分轨][398.22MB]
- ZWEI《迟暮的花 (Explicit)》[320K/MP3][57.16MB]