当前比较流行的前后端分离架构,即后端服务提供RestFull接口,经常遇到的一个问题就是跨域问题,(什么叫跨域问题,可自行百度),解决跨域问题有很多种方法,其中常用的有:
1、Jsonp跨域
2、Nginx反响代理
3、Cros
4、…
本文主要讲解CROS跨域问题的解决方案。
CROS:跨源资源共享(Cross-Origin Resource Sharing)
跨站 HTTP 请求(Cross-site HTTP request)是指发起请求的资源所在域不同于该请求所指向资源所在的域的 HTTP 请求。比如说,域名A(http://a.com)的某 Web 应用程序中通过<img>标签引入了域名B(http://b.com)站点的某图片资源(http://b.com/image.jpg),域名A的那 Web 应用就会导致浏览器发起一个跨站 HTTP 请求。在当今的 Web 开发中,使用跨站 HTTP 请求加载各类资源(包括CSS、图片、JavaScript 脚本以及其它类资源),已经成为了一种普遍且流行的方式。
出于安全考虑,浏览器会限制脚本中发起的跨站请求,将返回结果拦截。比如,使用 XMLHttpRequest 对象发起 HTTP 请求就必须遵守同源策略(same-origin policy)。 具体而言,Web 应用程序能且只能使用 XMLHttpRequest 对象向其加载的源域名发起 HTTP请求,而不能向任何其它域名发起请求。
隶属于 W3C 的 Web 应用工作组( Web Applications Working Group )推荐了一种新的机制,即跨源资源共享(Cross-Origin Resource Sharing (CORS))。这种机制让Web应用服务器能支持跨站访问控制,从而使得安全地进行跨站数据传输成为可能。CROS标准通过新增一系列 HTTP 头,让服务器能声明那些来源可以通过浏览器访问该服务器上的资源。另外,对那些会对服务器数据造成破坏性影响的 HTTP 请求方法(特别是 GET 以外的 HTTP 方法,或者搭配某些MIME类型的POST请求),标准强烈要求浏览器必须先以 OPTIONS 请求方式发送一个预请求(preflight request),从而获知服务器端对跨源请求所支持 HTTP 方法。在确认服务器允许该跨源请求的情况下,以实际的 HTTP 请求方法发送那个真正的请求。服务器端也可以通知客户端,是不是需要随同请求一起发送信用信息(包括 Cookies 和 HTTP 认证相关数据)。
SpringBoot工程/集成方案
有多种方案:
1、实现 WebMvcConfigurer 接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
@Configuration public class LowCodeWebMvcConfigurer implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { WebMvcConfigurer.super.addCorsMappings(registry); registry.addMapping("/**") .allowedHeaders("Origin, X-Requested-With, Content-Type, Accept, token") .allowedMethods("GET", "POST", "DELETE", "PUT", "OPTIONS") .allowedOriginPatterns("*") // .allowedOrigins("*") .allowCredentials(true) ; } } |
注意:这里把 allowedOrigins(“*”) 注解掉了,主要原因是,Spring 5.0以上,有个限制,当allowCredentials=true的时候,不允许allowedOrigins直接传“*”号,会抛出异常:
1 2 3 4 5 6 7 |
java.lang.IllegalArgumentException: When allowCredentials is true, allowedOrigins cannot contain the special value "*" since that cannot be set on the "Access-Control-Allow-Origin" response header. To allow credentials to a set of origins, list them explicitly or consider using "allowedOriginPatterns" instead. at org.springframework.web.cors.CorsConfiguration.validateAllowCredentials(CorsConfiguration.java:453) ~[spring-web-5.3.6.jar:5.3.6] at org.springframework.web.servlet.handler.AbstractHandlerMapping.getHandler(AbstractHandlerMapping.java:532) ~[spring-webmvc-5.3.6.jar:5.3.6] at org.springframework.web.servlet.DispatcherServlet.getHandler(DispatcherServlet.java:1254) ~[spring-webmvc-5.3.6.jar:5.3.6] at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1036) ~[spring-webmvc-5.3.6.jar:5.3.6] .... ... 35 more |
1 |
解决方案,就是 用 allowedOriginPatterns(“*”) 替代,或者 限制好域名。
2、Filter里实现
在自己实现的Filter里增加以下几行代码:
1 2 3 4 5 6 7 |
String curOrigin = request.getHeader("Origin"); log.info("CrosFilter Origin={}",curOrigin); //设置允许跨域的配置 response.setHeader("Access-Control-Allow-Origin", curOrigin); response.setHeader("Access-Control-Allow-Credentials", "true"); response.setHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, DELETE, OPTIONS, PATCH"); response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, token"); |
3、Controller里直接增加@CrossOrigin
在需要配置跨域的请求方法上或者类上,增加 @CrossOrigin 注解,注解里可以配置 Origin 和 Header。
本地测试方法:
再浏览器里,任意打开一个非同域下的网站,F12,在浏览器控制台里输入:
1 2 3 4 5 6 7 |
var xhr = new XMLHttpRequest(); xhr.open('GET', 'https://xxxx.com/xxxx'); xhr.send(null); xhr.onload = function(e) { var xhr = e.target; console.log(xhr.responseText); } |
回车,如果正常显示结果,证明访问成功。
转载请注明:刘召考的博客 » SpringBoot项目-解决CROS跨域问题