引言
跨域问题一般会在前后端分离的项目中遇到,跨域的产生是因为浏览器为了安全设置的同源策略,只有协议(http/https)、域名(www.test.com)、端口(8080/8081…)三者都相同时才不会产生跨域问题;
这也解释了为什么前后端分离的项目会有跨域问题,就比如我们在同一台服务器上开发,前端的url为:http://127.0.0.1:3000,而后端的url为:http://127.0.0.1:8080,两者端口都不同如果相互访问定然会产生跨域问题;
如图:
前端http://localhost:3000向后端发送请求:http://localhost:8080/api/user/search/tags,但是因为端口号不同,于是请求失败,报错信息也显示跨域策略阻塞:has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
下面就分享一下我对于跨域问题的解决方法;
解决方法
下面就是几种方法解决上面案例;
WebMvcConfig配置类跨域配置
可以通过自定义配置类实现跨域请求,具体配置如下:
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
// 设置允许跨域的路径
registry.addMapping("/**")
// 设置允许跨域请求的域名
// 当Credentials证书为true时,Origin不能为星号,需为具体的ip地址(如果接口不带cookie,ip无需设成具体ip)
.allowedOrigins("http://localhost:3000")
// 是否允许证书 不再默认开启
.allowCredentials(true)
// 设置允许的方法
.allowedMethods("*")
// 跨域允许时间
.maxAge(3600);
}
}
前端向后端请求:
可以看到请求成功,并且跨域允许的url为配置的前端域名:http://localhost:3000
注解@CrossOrigin实现跨域
这个方法比上面方法就简单太多了,直接在后端Controller类上加上该注解,默认允许所有跨域请求,但是最好还是标明请求域名:
这样也可以实现跨域访问,相对于配置来说简单些,但是也有缺点,最后一块说;
结果就不展示了,和之前一样;
GateWay网关配置
网关配置一般是在微服务项目中单独有一个网关模块,因为微服务中的所有请求都要通过网关过滤,所以请求首先就是到网关,我们可以通过在网关服务中配置跨域:
在网关模块的application.yml配置文件中配置跨域:
# 跨域配置:
spring:
cloud:
gateway:
globalcors: # 全局的跨域处理
add-to-simple-url-handler-mapping: true # 解决options请求被拦截问题
corsConfigurations:
'[/**]': # 设置拦截哪些请求,/**表示拦截一切请求
allowedOrigins: # 允许哪些网站的跨域请求
- "http://localhost:3000"
allowedMethods: # 允许的跨域ajax的请求方式
- "GET"
- "POST"
- "DELETE"
- "PUT"
- "OPTIONS"
allowedHeaders: "*" # 允许在请求中携带的头信息
allowCredentials: true # 是否允许携带cookie
maxAge: 360000 # 这次跨域检测的有效期
我们也可以自定义配置文件配置:
/**
* 跨域统一配置
*/
@Configuration
public class CorsConfig {
// 处理跨域
@Bean
public CorsWebFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
// 允许的请求头
config.addAllowedMethod("*");
// 允许的请求源 (如:http://localhost:8080)
config.addAllowedOrigin("http://localhost:3000");
// 允许的请求方法 ==> GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE
config.addAllowedHeader("*");
// URL 映射 (如: /admin/**)
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
source.registerCorsConfiguration("/**", config);
return new CorsWebFilter(source);
}
}
这两种方法都可以实现网关的跨域配置;
总结
大体上介绍了三种解决跨域的方法,那么实际该如何选择呢?
-
@CrossOrigin注解:这种方法适合单体项目,比较灵活,实现简单;每一个Controller接口允许的跨域url都很清楚,但是Controller接口多了后就很麻烦;
-
WebMvcConfig配置类:这种方法适合单体项目,并且如果你觉得在每一个Controller上添加@CrossOrigin注解很麻烦的话,就可以使用这个方法;
-
GateWay网关配置:这种方法适合微服务项目,并且我分享的两种方法还是比较建议使用第一种方法,直接在application.yml文件配置;
需要注意一点:如果网关配置了跨域,那么就不要在其他地方配置跨域,比如再在Controller上加@CrossOrigin注解,如果这样跨域相当于没有配置,会失效;