项目场景:
前端使用axios调用后端接口报错:
Access to XMLHttpRequest at 'http://localhost:8080/article/add' from origin 'http://127.0.0.1:5500' 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 resource
问题描述
后端项目正常运行,调用接口时没有日志输入,查看页面的控制台输出发现报错:
Access to XMLHttpRequest at 'http://localhost:8080/article/add' from origin 'http://127.0.0.1:5500' 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 resource
前端vue项目代码如下:
axios({
method: 'post',
url: 'http://localhost:8080/article/add',
data: article
}).then(result => {
document.write("yes!!!");
console.log(result.data);
}).catch(err => {
console.log(err);
});
}
原因分析:
在Spring MVC中,
addCorsMappings
和addInterceptors
是两种不同的配置设置,它们分别用于配置跨域资源共享(CORS)和拦截器(Interceptors)。
- CORS (Cross-Origin Resource Sharing):
这是为了让Web应用可以跨域访问资源,即允许一个域名下的网页向另一个域名发起请求。在Spring
MVC中,可以通过WebMvcConfigurer接口的addCorsMappings方法来全局配置CORS策略。 - Interceptors (拦截器):
拦截器是一种设计模式,用于在请求处理前后执行某些操作,如日志记录、性能监控、权限检查等。在Spring
MVC中,你可以通过WebMvcConfigurer接口的addInterceptors方法来注册自定义的拦截器。
至于为什么
addCorsMappings
通常会在addInterceptors
之前配置,这是因为CORS配置应该尽早被处理,以确保任何后续的拦截器或请求处理逻辑都能在正确的跨域策略下运行。CORS过滤器通常被认为是较低级别的中间件,它需要在实际业务逻辑之前处理好跨域请求的响应头信息。
例如,如果你的CORS配置允许特定的请求方法或来源,那么这些设置需要在请求到达拦截器之前就已经确定下来。如果CORS配置在拦截器之后才被处理,可能会导致一些跨域请求因为不符合预期的CORS策略而失败。
因此,为了确保跨域请求能够按照预期工作,并且任何拦截器的操作不会影响到CORS的响应头设置,通常的做法是先配置CORS,然后再添加拦截器。这并不是一个硬性规定,而是出于逻辑上的合理性和最佳实践考虑。
解决方案:
后端服务器配置CORS
@Override
public void addCorsMappings(CorsRegistry registry) {
// 设置允许跨域的路径
registry.addMapping("/**")
.allowedOrigins("http://127.0.0.1:5500")
// 设置允许跨域请求的域名
.allowedOriginPatterns("*")
// 是否允许cookie
.allowCredentials(true)
// 设置允许的请求方式
.allowedMethods("GET", "POST", "DELETE", "PUT")
// 设置允许的header属性
.allowedHeaders("*")
// 跨域允许时间
.maxAge(3600);
}
但是发现还是有问题,说明项目中出现的问题与我相同,此时需要检查一下WebConfig类里面的顺序。由于我的项目中先配置了登录拦截器,所以加入CROS时放在了代码后面,但是仍然出现报错
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 登录接口和注册接口不拦截
registry.addInterceptor(loginInterceptor).excludePathPatterns("/user/login","/user/register");
}
但是在调整完两个方法在内部的顺序后,发现问题解决。
@Override
public void addCorsMappings(CorsRegistry registry) {
// 设置允许跨域的路径
registry.addMapping("/**")
.allowedOrigins("http://127.0.0.1:5500")
// 设置允许跨域请求的域名
.allowedOriginPatterns("*")
// 是否允许cookie
.allowCredentials(true)
// 设置允许的请求方式
.allowedMethods("GET", "POST", "DELETE", "PUT")
// 设置允许的header属性
.allowedHeaders("*")
// 跨域允许时间
.maxAge(3600);
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 登录接口和注册接口不拦截
registry.addInterceptor(loginInterceptor).excludePathPatterns("/user/login","/user/register");
}