SpringMvc 跨域处理
导读
由于浏览器对于JavaScript的同源策略的限制,导致A网站(Ajax请求)不能通过JS去访问B网站的数据,于是跨域问题就出现了。
跨域指的是域名、端口、协议的组合不同就是跨域。
- http://www.chenyanbin.com/
- https://www.chenyanbin.com/
- http://www.chenyanbin.cn
- http://www.chenyanbin.com:8080/
为什么要有同源策略?
举个例子:比如一个黑客程序,他利用IFrame把真正的银行登录页面嵌套到他的页面上,当你使用真实的用户名,密码登录时,他的页面就可以通过JavaScript读取到你的表单中input中的内容,这样用户名、密码就轻松到手啦。

如何解决跨域?
解决跨域的方式有多种,比如基于JavaScript的解决方式、基于Jquery的JSONP、以及基于CORS的方式。
JSONP和CORS的区别之一:JSONP只能解决get方式提交、CORS不仅支持GET方式,同时还支持POST提交方式。
我们重点讲解CORS跨域方式。
什么是CORS?
CORS是一个W3C标准,全称是“跨域资源共享”(Cross-origin resource sharing)。
它允许浏览器向跨资源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。
CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,浏览器不能低于IE10。
CORS原理:只需要向响应头header中注入:Access-Control-Allow-Origin,这样浏览器检测到header中的:Access-Control-Allow-Origin,则就可以跨域操作了。
CORS请求分类标准
浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple-request)。
简单请求

凡是不同时满足上面两个条件,就属于非简单请求。
浏览器对这两种请求的处理,是不一样的。
对于一个简单请求,浏览器直接发出CORS请求,具体来说,就是在头信息之中,加上一个Origin字段。
请求信息

响应信息

字段说明
- Access-Control-Allow-Origin:该字段是必须的。它的值要么是请求时Origin字段的值,要么是一个*,表示接收任意域名的请求。
- Access-Control-Allow-Credentials:该字段可选。它的值是一个布尔值,表示是否允许发送Cookie。默认情况下,Cookie不包括在CORS请求之中,设为True,即表示服务器明确许可,Cookie可以包含在请求中,一起发送给服务器。这个值也只能设为True,如果服务器不要浏览器发送Cookie,删除即可。
非简单请求
非简单请求是那种对服务器有特殊要求的请求,比如请求方法是PUT或者DELETE,或者Content-Type字段的类型是:application/json。
非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为“预检”请求(preflight)。
浏览器先咨问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错。
请求信息
Http请求的方式是put,并发送一个自定义头信息:X-Custom-Header。
浏览器发现,这是一个非简单请求,就自动发出一个“预检”请求,要求服务器确认可以这样请求。下面是这个“预检”请求的HTTP头信息。

“预检”请求用的请求方法是OPTIONS,表示这个请求是用来咨问的。头信息里面,关键字端是Origin,表示请求来自那个源。
除了Origin字段,“预检”请求的头信息包括两个特殊字段。
- Access-Control-Request-Method:该字段是必须的,用来列出浏览器的CORS请求会用到哪些HTTP方法,上例是PUT。
- Access-Control-Request-Header:该字段是一个逗号分隔的字符串,指定浏览器CORS请求会额外发送的头信息字段,上例是X-Custom-Header。
一旦服务器通过了“预检”请求,以后每次浏览器正常的CORS请求,就都跟简单请求一样了。会有一个Origin头信息字段。服务器的回应,也都会有一个Access-Control-Allow-Origin头信息字段。
CORS实现
使用SpringMvc的拦截器实现
具体的【SpringMvc 拦截器】参考
跨域不提交Cookie
package com.cyb.ssm.controller; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.HandlerInterceptor; public class MyHandlerIntercepter implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
System.out.println("Origin:"+request.getHeader("Origin"));
if (request.getHeader("Origin") != null) {
response.setContentType("text/html;charset=UTF-8");
// 允许哪一个URL
response.setHeader("Access-Control-Allow-Origin", "*");
// 允许那种请求方法
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("XDomainRequestAllowed", "1");
System.out.println("正在跨域");
}
return true; //True:允许访问;False:不允许访问
}
}
拦截器的配置,请参考【SpringMvc 拦截器】
跨域提交Cookie
Access-Control-Allow-Credentials为True的时候,Access-Control-Allow-Origin一定不能设置为“*”,否则报错。
如果有多个拦截器,一定要把处理跨域请求的拦截器放到首位。
AJAX

JAVA代码
public class AllowOriginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object arg2) throws Exception {
if (request.getHeader("Origin") != null) {
response.setContentType("text/html;charset=UTF-8");
// 允许哪一个URL 访问 request.getHeader("Origin") 根据请求来的url动态允许
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
// 允许那种请求方法
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE,HEAD");
response.setHeader("Access-Control-Max-Age", "0");
// 允许请求头里的参数列表
response.setHeader("Access-Control-Allow-Headers",
"Origin, No-Cache, X-Requested-With, If-Modified-Since, Pragma, Last-Modified, Cache-Control, Expires, Content-Type, X-E4M-With,userId,token");
// 允许对方带cookie访问
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("XDomainRequestAllowed", "1");
System.out.println("正在跨域");
}
return true;
}
}
SpringMvc 跨域处理的更多相关文章
- SpringMVC跨域问题排查以及源码实现
SpringMVC跨域问题排查以及源码实现 最近一次项目中,将SpringMVC版本从4.1.1升级到4.3.10,出现跨域失败的情况.关于同源策略和跨域解决方案,网上有很多资料. 项目采用的方式是通 ...
- SpringMvc跨域支持
SpringMvc跨域支持 在controller层加上注解@CrossOrigin可以实现跨域 该注解有两个参数 1,origins : 允许可访问的域列表 2,maxAge:飞行前响应的缓存持续 ...
- 关于springmvc跨域
spingMVC 3.X跨域 关于跨域问题,主要用的比较多的是cros跨域. 详细介绍请看https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Acces ...
- springmvc跨域
//mvc默认是text/plain;charset=ISO-8859-1@RequestMapping(value = "/xxx", produces = "appl ...
- springmvc跨域(转)
跨域资源共享 CORS 详解 原文链接:http://www.ruanyifeng.com/blog/2016/04/cors.html 作者: 阮一峰 日期: 2016年4月12日 CORS是 ...
- (H5)FormData+AJAX+SpringMVC跨域异步上传文件
最近都没时间整理资料了,一入职就要弄懂业务,整天被业务弄得血崩. 总结下今天弄了一个早上的跨域异步上传文件.主要用到技术有HTML5的FormData,AJAX,Spring MVC. 首先看下上传页 ...
- springmvc跨域+token验证(app后台框架搭建二)
这是app后台框架搭建的第二课,主要针对app应用是跨域的运用,讲解怎么配置跨域服务:其次讲解怎么进行token验证,通过拦截器设置token验证和把token设置到http报文中.主要有如下: ...
- springmvc跨域+token验证
1)app后台跨域设置 2)拦截器中设置http报文header中token 3)token的生成实现 ==================================== ...
- springmvc跨域问题的解决
如果只想对某个方法开启跨域设置: controller上添加注解: @CrossOrigin(maxAge = 3600) 在特定的方法上添加注解: @CrossOrigin("*" ...
随机推荐
- python脚本 环境准备
现在的公司用 Python 做 Web 开发,入职到现在为止(三个月),算是入门了 Python Web 开发 但是 Python 本身是脚本语言,我还从来没有体会到脚本语言能给日常工作带来的便利 就 ...
- centos6官网镜像dvd1和dvd2的解释
- 后台开发小白必学服务器框架——UDPServer
毕业后加入了一家大型的互联网公司的音视频产品部门做后台开发,其实我本身是学习自动化的,研究生的方向嵌入式系统,对互联网可是一知半解,因此能进入这样一个大公司还是很幸运的. 刚开始工作的半年应该是在上份 ...
- linux启动与登录
1.............rescue..............进入维护模式 (grub选项吧这是) 2.linux启动的幕后过程: 1 加电 (再一次联想服务器升级内存时,加电后有个黄色报警,过 ...
- Class文件结构全面解析(下)
接上回书 书接上一回,分享了Class文件的主要构成,同时也详细分析了魔数.次版本号.主版本号.常量池集合.访问标志的构造,接下来我们就继续学习. 欢迎关注微信公众号:万猫学社,每周一分享Java技术 ...
- 【Elasticsearch 7 探索之路】(四)Analyzer 分析
上一篇,什么是倒排索引以及原理是什么.本篇讲解 Analyzer,了解 Analyzer 是什么 ,分词器是什么,以及 Elasticsearch 内置的分词器,最后再讲解中文分词是怎么做的. 一.A ...
- 掌握Python系统管理-调试和分析脚本2- cProfile和timeit
调试和分析在Python开发中发挥着重要作用. 调试器可帮助程序员分析完整的代码. 调试器设置断点,而剖析器运行我们的代码,并给我们执行时间的详细信息. 分析器将识别程序中的瓶颈.我们将了解pdb P ...
- [ASP.NET Core 3框架揭秘] 配置[1]:读取配置数据[上篇]
提到"配置"二字,我想绝大部分.NET开发人员脑海中会立即浮现出两个特殊文件的身影,那就是我们再熟悉不过的app.config和web.config,多年以来我们已经习惯了将结构化 ...
- 删除节点(removeChild())
remoceChild():方法将从一个给定元素里删除一个子节点: reference = element.removeChild(node); 这个方法的返回值是一个指向已经被删除的子节点的引用指针 ...
- cas的客户端应用是负载均衡,单点退出怎么办?
之前的项目一直是单节点,这次在生产系统中使用了负载均衡,一个应用部署了两个节点,负载均衡策略未知.这样在使用时发现了这么一个问题:在单点退出后,应用有时候可以退出,但有时还在登陆状态,这就很郁闷了. ...