springmvc【问题1】跨域
2019独角兽企业重金招聘Python工程师标准>>>
问题介绍:什么是跨域
简单的说即为浏览器限制访问A站点下的js代码对B站点下的url进行ajax请求。比如说,前端域名是www.abc.com,那么在当前环境中运行的js代码,出于安全考虑,访问www.xyz.com域名下的资源,是受到限制的。现代浏览器默认都会基于安全原因而阻止跨域的ajax请求,这是现代浏览器中必备的功能,但是往往给开发带来不便。特别是对我这样后台开发人员来讲,这个事情简直神奇。
但跨域的需求却一直都在,为了跨域,勤劳勇敢的程序猿们想出了许许多多的方法,例如,jsonP、代理文件等等。但这些做法增加了许多不必要的维护成本,而且应用场景也有许多限制,例如jsonP并非XHR,所以jsonP只能使用GET传递参数。更详细的资料可以看这里 Web应用跨域访问解决方案汇总
CORS协议
如今的JS大有一统天下的趋势,浏览器已经成了大多应用最好的安身之所。哪怕在移动端也有各种Hybird方案,在本地文件系统的Web页面,也有需要获取外部数据的需求,而这些需求也必然是跨域的。在寻找跨域解决方案时,发现了最优雅解决方案就是HTML5来带了的“Cross-Origin Resource Sharing”的新特性,来赋予开发者权力决定资源是否允许被跨域访问。
CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。
它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。
为什么说它优雅呢?
整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。
因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。
解决这个问题的关键就落在了我这个负责后台的程序猿身上。
看看文档也不是什么难事嘛,就是需要在http头中设置Access-Control-Allow-Origin来决定需要允许哪些站点来访问。关于CROS协议更详细内容参考跨域资源共享 CORS 详解
CROS常见header
CORS具有以下常见的header
Access-Control-Allow-Origin: http://kbiao.me Access-Control-Max-Age: 3628800 Access-Control-Allow-Methods: GET,PUT, DELETE Access-Control-Allow-Headers: content-type
"Access-Control-Allow-Origin"表明它允许" http://kbiao.me "发起跨域请求
"Access-Control-Max-Age"表明在3628800秒内,不需要再发送预检验请求,可以缓存该结果(上面的资料上我们知道CROS协议中,一个AJAX请求被分成了第一步的OPTION
预检测请求和正式请求)
"Access-Control-Allow-Methods"表明它允许GET、PUT、DELETE的外域请求
"Access-Control-Allow-Headers"表明它允许跨域请求包含content-type头
常规解决方案
知道了问题的原因,也知道了配套的解决办法,现在就让我们来实现解决。思路很简单,当前端要请求跨域资源时候,我们给它加上响应的响应头即可。很显然我们自己定义一个过滤器是最简单不过了。
/** * Created by kangb on 2016/5/10. */ @Component public class myCORSFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletResponse response = (HttpServletResponse) servletResponse; String origin = (String) servletRequest.getRemoteHost()+":"+servletRequest.getRemotePort(); response.setHeader("Access-Control-Allow-Origin", "*"); response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE"); response.setHeader("Access-Control-Max-Age", "3600"); response.setHeader("Access-Control-Allow-Headers", "x-requested-with,Authorization"); response.setHeader("Access-Control-Allow-Credentials","true"); filterChain.doFilter(servletRequest, servletResponse); } @Override public void destroy() { } }
@Component 是Spring的注解,关键部分在doFilter中,添加了我们需要的头,option
是预检测需要所以需要允许,Authorization
是做了oauth2登录响应所必须的,Access-Control-Allow-Credentials
表示允许cookies。都是根据自己项目的实际需要配置。
再配置Web.xml使得过滤器生效
<filter> <filter-name>cors</filter-name> <filter-class>·CLASS_PATH·.myeCORSFilter</filter-class> </filter> <filter-mapping> <filter-name>cors</filter-name> <url-pattern>/api/*</url-pattern> </filter-mapping>
接下来前端就可以像往常一样使用AJAX请求获得资源了,完全不需要做出什么改变。
SPRING 4中更优雅的办法
SpringMVC4提供了非常方便的实现跨域的方法。在requestMapping中使用注解。
@CrossOrigin(origins = “http://kbiao.me”)
全局实现 .定义类继承WebMvcConfigurerAdapter,设置跨域相关的配置
public class CorsConfigurerAdapter extends WebMvcConfigurerAdapter{ @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/api/*").allowedOrigins("*"); } }
将该类注入到容器中:
<bean class="com.tmall.wireless.angel.web.config.CorsConfigurerAdapter"></bean>
更详细的内容参考Spring 官方的hello world案例Enabling Cross Origin Requests for a RESTful Web Service
http://spring.io/guides/gs/rest-service-cors/或者使用git下载示例源码
https://github.com/spring-guides/gs-rest-service-cors.git
第二部分
关于跨域问题,主要用的比较多的是cros跨域。
详细介绍请看https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS
但是,在springmvc+angularjs下支持跨域请求时,出现复杂跨域场景(post + json)失败的情况。
开始的跨域配置如下:
public class CrossInterceptor extends HandlerInterceptorAdapter {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {response.addHeader("Access-Control-Allow-Origin","*");response.addHeader("Access-Control-Allow-Methods","*");response.addHeader("Access-Control-Max-Age","100");response.addHeader("Access-Control-Allow-Headers", "Content-Type");response.addHeader("Access-Control-Allow-Credentials","false");return super.preHandle(request, response, handler);}}
spring-dispatcher-servlet.xml中配置如下:
<mvc:interceptors><mvc:interceptor><mvc:mapping path="/**/*"/><bean class="cn.***.filter.CrossInterceptor" /></mvc:interceptor> </mvc:interceptors>
针对简单跨域没问题。但是针对post+json请求却失败,提示跨域失败。
跟踪springmvc源码到FrameworkServlet中的doOption方法,发现,接受了option预检,但是spring主动返回allow,没有支持跨域的配置。
因此,加入新的配置如下:
public class CrossFilter extends OncePerRequestFilter {@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {if (request.getHeader("Access-Control-Request-Method") != null && "OPTIONS".equals(request.getMethod())) {// CORS "pre-flight" requestresponse.addHeader("Access-Control-Allow-Origin", "*");response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");response.addHeader("Access-Control-Allow-Headers", "Content-Type");response.addHeader("Access-Control-Max-Age", "1800");//30 min }filterChain.doFilter(request, response);} }
web.xml配置如下:
<filter><filter-name>cors</filter-name><filter-class>cn.***.filter.CrossFilter</filter-class> </filter> <filter-mapping><filter-name>cors</filter-name><url-pattern>/*</url-pattern> </filter-mapping>
此时,option请求被CrossFilter过滤器接入并赋予跨域响应头,同时也进入FrameworkServlet中的doOption方法。查看浏览器控制台,发现option请求返回支持跨域信息,后续的post请求进入controller。
- springMVC 4.X跨域
升级spring版本的后,上述跨域并不支持所有浏览器。经测试,Safari正常,chrome异常。重新翻了一下最新的文档后,得到最新的跨域配置如下:
<mvc:cors><mvc:mapping path="/**" allowed-origins="*" allow-credentials="true" max-age="1800" allowed-methods="GET,POST,OPTIONS"/></mvc:cors>
相比3.x系列,简单了很多。
项目中使用的拦截器,配置如下:
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import com.ztb.context.WebContext;
public class CrossInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
response.addHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
response.addHeader("Access-Control-Allow-Methods", "POST, GET, DELETE, PUT");
response.addHeader("Access-Control-Allow-Headers", "Content-Type");
response.addHeader("Access-Control-Allow-Credentials", "true");
(1) WebContext.getServletResponse().setHeader("Access-Control-Allow-Credentials", "true"); // 是否支持cookie跨域
return super.preHandle(request, response, handler);
}
}
注释
(1)中使用的方法
public static HttpServletResponse getServletResponse() {
return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
}
pring.xml中配置如下:
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**/*"/>
<bean class="com.**.filter.CrossInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
转载于:https://my.oschina.net/maojindaoGG/blog/1616121
springmvc【问题1】跨域相关推荐
- 使用SpringMVC解决Ajax跨域问题
使用SpringMVC解决Ajax跨域问题 参考文章: (1)使用SpringMVC解决Ajax跨域问题 (2)https://www.cnblogs.com/mengyao/p/6294787.ht ...
- SpringMvc 3.x跨域+ajax请求
一.Cors,实现Js跨域访问Tomcat下资源(步骤如下) web.xml配置 <filter> <filter-name>CorsFilter</filter-nam ...
- 最全面的SpringMVC教程(三)——跨域问题
前言 本文为 [SpringMVC教程]跨域问题 相关内容介绍.当一个请求url的协议.域名.端口三者之间任意一个与当前页面url不同时,就会产生跨域.那么究竟什么是跨域,跨域问题该如何解决,本文具体 ...
- nginx解决浏览器跨域问题_前端通过Nginx反向代理解决跨域问题
在前面写的一篇文章SpringMVC解决跨域问题,我们探讨了什么是跨域问题以及SpringMVC怎么解决跨域问题,解决方式主要有如下三种方式: JSONP CORS WebSocket 可是这几种方式 ...
- CrossOrigin注解的方式实现接口的跨域访问
springMVC接口实现跨域访问: springMVC框架通过@CrossOrigin注解的方式实现接口的跨域访问 java示例代码: package com.jmst.httpservice; i ...
- ajax跨域请求时 会出现什么问题,在用AJAX跨域请求时遇到的问题
刚刚接触ajax就遇到一个词--跨域. 在我百度了各种资料以后总结了一句话:"只要不是在一个协议.域.名端口下,都属于跨域(127.0.0.1本地也属于跨域)". 在做ajax请求 ...
- 前后端分离后产生的跨域问题sessionid丢失,cookies无法写入等
文章目录 前言 一.会话机制 1. 何为一次会话,会话从什么时候开始,从什么时候结束? 2.cookies如何保持会话,它的工作流程? 3.session原理分析: 实例记录sessionid变化(前 ...
- SpringMvc+ajax实现文件跨域上传
最近开始学习SpringMVC框架,在学习数据绑定的时候,发现可以使用@RequestParam注解绑定请求数据,实现了文件上传.但是如果一个项目是前后端分离的,前端系统向后端服务上传文件该怎么解决了 ...
- 【SpringMVC】与权限拦截器冲突导致的Cors跨域设置失效问题
问题描述 前端域名FE.com向后端域名BE.com分别请求访问优惠券的列表和提交新增的优惠券,API设计所用的Method分别为Get和Post,结果为前一次访问成功而后一次访问失败.这两次请求都是 ...
最新文章
- ZooKeeper 如何保证数据一致性
- 身为初学Java的你,这些IDE的优缺点你都知道吗?
- java 7个数排序_JAVA基础(7)-数组的排序
- Oracle常见操作和命令
- vue-router学习第一天
- 友链导航源码php,2020优化版导航源码自动收录秘趣导航批量检查友链有效性导航源码...
- 林淮川孙玄:分布式锁选型背后的架构设计思维【附源码】
- HTMLParser错误解决
- 鼠标光标变成方块怎么办
- python归一化 增大差异_python-面向对象进阶
- CSS中已经定义宽度的样式 英文不执行换行
- springboot+网络空间安全实验教学中心门户网站 毕业设计-附源码191220
- 最优解问题——PuLP解决线性规划问题(一)
- 新机安装指南(软件推荐)
- node.js -- 手把手教你搭建 电商平台
- Android记账本APP开发进阶版
- NDK开发QQ语音变声
- 计算机管理的磁盘管理简单卷,小编教你磁盘管理新建简单卷怎么做
- 《等着我吧,我会回来》 苏·西蒙诺夫
- multisim 高低电平点亮灯证明