springcloud gatway网关解决跨域问题,开发时,遇到application.yml,设置如下,但我在实际开发中不生效:
spring:
cloud:
gateway:
globalcors:
corsConfigurations:
'[/**]':
allowedOrigins: "*"
allowedMethods: "*"
解决这个问题,可以从两方面入手,一种方案是在微服务各自的业务模块中实现,即在SpringBoot层实现,另外一种方案就是在Gateway层实现。
SpringBoot层实现的三种方案:
解决方案一:在Controller上添加@CrossOrigin注解
这种方式适合只有一两个rest接口需要跨域或者没有网关的情况下,这种处理方式就非常简单,适合在原来基代码基础上修改,影响比较小。
@CrossOrigin //跨源资源共享注解
@RestController
@RequestMapping("bill")
@RefreshScope //配置文件改变自动刷新属性
public class BillController {
//方法体........
}
解决方案二:增加WebMvcConfigurer全局配置
如果有大量的rest接口的时候,显然第一种方案已经不适合了,工作量大,也容易出错,那就通过全局配置的方式,允许SpringBoot端所有的rest接口都支持跨域访问,这个时候就需要考虑安全性的问题。
代码如下:
@Configuration
public class MyConfiguration {
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowCredentials(true).allowedMethods("GET");
}
};
}
}
解决方案三:结合Filter使用
这种方案的使用场景跟第二种方案类似,只不过换成使用Filter的方式实现。
在spring boot的主类中,增加一个CorsFilter
/**
* attention:简单跨域就是GET,HEAD和POST请求,但是POST请求 的"Content-Type"只能是application/x-www-form-urlencoded, multipart/form-data 或 text/plain
* 反之,就是非简单跨域,此跨域有一个预检机制,说直白点,就是会发两次请求,一次OPTIONS请求,一次真正的请求
*/
@Bean
public CorsFilter corsFilter() {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
final CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true); // 允许cookies跨域
config.addAllowedOrigin("*");// #允许向该服务器提交请求的URI,*表示全部允许,在SpringMVC中,如果设成*,会自动转成当前请求头中的Origin
config.addAllowedHeader("*");// #允许访问的头信息,*表示全部
config.setMaxAge(18000L);// 预检请求的缓存时间(秒),即在这个时间段里,对于相同的跨域请求不会再预检了
config.addAllowedMethod("OPTIONS");// 允许提交请求的方法,*表示全部允许
config.addAllowedMethod("HEAD");
config.addAllowedMethod("GET");// 允许Get的请求方法
config.addAllowedMethod("PUT");
config.addAllowedMethod("POST");
config.addAllowedMethod("DELETE");
config.addAllowedMethod("PATCH");
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
以上这种方案如果微服务多的话,需要在每个服务的主类上都加上这么段代码,增加了维护量。
以上三种方案都是在SpringBoot的基础上实现的解决方案,在模块较多或者接口较多的情况下不易维护。
SpringCloud实现的方案:
解决方案一:在Gateway里添加Filter代码类
public class CorsWebFilter implements WebFilter {
private static final String ALL = "*";
private static final String MAX_AGE = "18000L";
@Override
public Mono<Void> filter(ServerWebExchange ctx, WebFilterChain chain) {
ServerHttpRequest request = ctx.getRequest();
String path = request.getPath().value();
ServerHttpResponse response = ctx.getResponse();
if ("/favicon.ico".equals(path)) {
response.setStatusCode(HttpStatus.OK);
return Mono.empty();
}
if (!CorsUtils.isCorsRequest(request)) {
return chain.filter(ctx);
}
HttpHeaders requestHeaders = request.getHeaders();
HttpMethod requestMethod = requestHeaders.getAccessControlRequestMethod();
HttpHeaders headers = response.getHeaders();
headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, requestHeaders.getOrigin());
headers.addAll(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, requestHeaders.getAccessControlRequestHeaders());
if (requestMethod != null) {
headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, requestMethod.name());
}
headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
headers.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, ALL);
headers.add(HttpHeaders.ACCESS_CONTROL_MAX_AGE, MAX_AGE);
if (request.getMethod() == HttpMethod.OPTIONS) {
response.setStatusCode(HttpStatus.OK);
return Mono.empty();
}
return chain.filter(ctx);
}
}
解决方案二:修改Gateway配置文件application.yml
spring:
cloud:
gateway:
globalcors:
corsConfigurations:
'[/**]':
#allowedOrigins: * # 这种写法或者下面的都可以,*表示全部
allowedOrigins:
- "http://localhost:8080"
allowedMethods:
- GET
- POST
- PUT
- DELETE