跨域问题。
什么是跨域
浏览器出于安全考虑,限制了JS发起跨站请求,使用XHR对象发起请求必须遵循同源策略(SOP:Same Origin Policy),跨站请求会被浏览器阻止。
什么是CORS
CORS是一个W3C标准,全称是”跨域资源共享”(Cross-origin resource sharing)。
它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。
以下内容引用自 阮一峰
CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。
整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。
因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。
解决方案
方法级别或者类级别跨域
当 应用中,仅有少量rest接口的时候,使用 CrossOrigin 注解 方式非常简单,只需在 controller 上添加该注解即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| @RestController public class HandlerScanController {
@CrossOrigin( allowCredentials="true", allowedHeaders="*", methods= {RequestMethod.GET, RequestMethod.POST, RequestMethod.DELETE, RequestMethod.OPTIONS, RequestMethod.HEAD, RequestMethod.PUT, RequestMethod.PATCH}, origins="*") @PostMapping("/confirm") public Response handler(@RequestBody Request json){ return null; } }
|
@CrossOrigin
: 可以添加到 method 和 class 上
- origins: 允许的来源列表. 他的值放置在HTTP协议的响应header的Access-Control-Allow-Origin
- allowedHeaders: 实际请求期间可以使用的请求标头列表. 值用于预检的响应header Access-Control-Allow-Headers
- methods: 支持的HTTP请求方法列表。 如果未定义,则使用由RequestMapping注释定义的方法
- exposedHeaders: 浏览器允许客户端访问的响应头列表。 在实际响应报头Access-Control-Expose-Headers中设置值
- allowCredentials: 它确定浏览器是否应该包含与请求相关的任何cookie
- maxAge: 预响应的高速缓存持续时间的最大时间(以秒为单位)。 值在标题Access-Control-Max-Age中设置。
对应不同的技术选型,跨域配置是不同的。全局的接口都支持跨域访问,容易引起安全性问题。
下面列举的配置方案 尽量不要共用。
SpringMvc 项目
对于 SpringMvc 项目,只需在 WebMvcConfigurerAdapter实现类里重写 addCorsMappings() 方法即可。
1 2 3 4 5 6 7 8 9 10
| @Configuration @EnableWebMvc public class CorsConfiguration extends WebMvcConfigurerAdapter { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedMethods("GET", "POST"); } }
|
Spring boot
声明一个 WebMvcConfigurer 即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @Configuration public class CorsConfiguration { @Bean public WebMvcConfigurer corsConfigurer() { return new WebMvcConfigurerAdapter() { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**"); } }; } }
|
Spring Security
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.cors().and() } @Bean CorsConfigurationSource corsConfigurationSource() { CorsConfiguration configuration = new CorsConfiguration(); configuration.setAllowedOrigins(Arrays.asList("https://example.com")); configuration.setAllowedMethods(Arrays.asList("GET","POST")); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", configuration); return source; } }
|
使用 filter
这种方案的使用场景跟上面的方案类似,只不过换成使用Filter的方式实现。
CorsFilter 为 org.springframework.web.filter.CorsFilter
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| public class Test{
@Bean public CorsFilter corsFilter() {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
final CorsConfiguration config = new CorsConfiguration(); config.setAllowCredentials(true); config.addAllowedOrigin("*"); config.addAllowedHeader("*"); config.setMaxAge(18000L); config.addAllowedMethod("OPTIONS"); config.addAllowedMethod("HEAD"); config.addAllowedMethod("GET"); config.addAllowedMethod("PUT"); config.addAllowedMethod("POST"); config.addAllowedMethod("DELETE"); config.addAllowedMethod("PATCH"); source.registerCorsConfiguration("/**", config);
return new CorsFilter(source); }
}
|
参考
跨域问题的五种解决方案
spring自带-rest-Service-cors
spring 跨域支持
阮一峰-CORS详解