Access to XMLHttpRequest at ‘https://a.com:8443/xxx’ from origin ‘https://b.com’ has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: No ‘Access-Control-Allow-Origin’ header is present on the requested resources.
1. 前言
CORS:Cross-origin resource sharing 跨域资源共享。
出于安全原因,浏览器禁止AJAX调用驻留在当前来源之外的资源。例如,当你在一个选项卡中检查你的银行账户时,你可以在另一个选项卡上有eviv.com网站。eviv.com的脚本不应该能够使用你的凭据向你的银行API发出AJAX请求(从你的账户提款!)。
所以这项安全原因会导致客户端URL的协议、端口和主机名都应该与其请求的服务器相匹配。但实际开发中可能需要不同源的资源。
跨域资源共享(CORS)是由大多数浏览器实现的W3C规范,它允许您以灵活的方式指定授权何种跨域请求,而不是使用一些不太安全、功能不太强大的黑客,如IFrame或JSONP。
开始分析:报错说的是不存在 Access-Control-Allow-Origin 标头。那么怎么加上 Access-Control-Allow-Origin 标头呢?让我们了解一下有关CORS的工作流程。
CORS请求(包括具有OPTIONS方法的飞行前请求)会自动发送到注册的各种HandlerMappings。由于CorsProcessor实现(默认情况下为DefaultCorsProcesser),它们处理CORS飞行前请求,并拦截CORS简单和实际的请求,以便添加相关的CORS响应标头(如访问控制允许起源)。
CorsConfiguration允许您指定应该如何处理CORS请求:允许的起源、标头、方法等。它可以通过多种方式提供:
AbstractHandlerMapping#setCorsConfiguration()
允许指定映射在路径模式(如/api/**
)上的多个CorsConfigoration的 Map。- 子类可以通过重写
AbstractHandlerMapping#getCorsConfiguration(Object,HttpServlet Request)
方法来提供自己的CorsConfigtion
。- 处理程序可以实现
CorsConfigurationSource
接口(就像ResourceHttpRequestHandler
现在所做的那样),以便为每个请求提供CorsConfiguration。
好,以上是理论分析,下面开始实践解决。
2. 添加部分CORS配置
将@CrossOrigin注释添加到@RequestMapping注释处理程序方法中,以便在其上启用CORS:
@CrossOrigin(maxAge = 3600)
@RestController
@RequestMapping("/account")
public class AccountController {
@CrossOrigin(origins = "http://domain2.com")
@GetMapping("/{id}")
public Account retrieve(@PathVariable Long id) {
// ...
}
@DeleteMapping("/{id}")
public void remove(@PathVariable Long id) {
// ...
}
}
如果有使用Spring Security,请确保在Spring Security级别启用CORS,以允许它利用在Spring MVC级别定义的配置。
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(final HttpSecurity http) throws Exception {
return http.cors().and()...
}
}
3. 使用全局CORS配置
除了细粒度的、基于注释的配置之外,可能还需要定义一些全局CORS配置。这类似于使用过滤器,但可以在Spring MVC中声明,并与细粒度的@CrossOrigin配置相结合。
为整个应用程序启用CORS非常简单:
@Configuration
public class MyConfiguration implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("*");
}
}
推荐使用全局配置。
主机名可视作域名。