Appearance
加入网关后设置跨域 @Configuration public class RouteConfiguration { @Bean public WebFilter corsFilter() { return (ServerWebExchange ctx, WebFilterChain chain) -> { ServerHttpRequest request = ctx.getRequest(); if (CorsUtils.isCorsRequest(request)) { ServerHttpResponse response = ctx.getResponse(); HttpHeaders headers = response.getHeaders(); headers.add("Access-Control-Allow-Origin", "*"); headers.add("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE, PATCH"); headers.add("Access-Control-Max-Age", "3600"); headers.add("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization"); headers.add("Access-Control-Expose-Headers", "Location"); headers.add("Access-Control-Allow-Credentials", "true"); if (request.getMethod() == HttpMethod.OPTIONS) { response.setStatusCode(HttpStatus.OK); return Mono.empty(); } } return chain.filter(ctx); }; } } 把这段代码在网关服务中配置后跨域就成功了
总的来说,解决方案:
NGINX解决跨域问题 在网关处解决跨域问题
这里记录自己在网关处解决跨域的方法: 技术:
- Springcloud Gateway
- springboot
版本:2.1.4
方法1: 在application.xml:
- spring:
- cloud: #
跨域配置
gateway:
globalcors:
cors-configurations:
'[/**]': #
匹配所有请求 allowedOrigins: "*" #跨域处理 允许所有的域 allowedMethods: # 支持的方法
- GET
- POST
- PUT
- DELETE
这样可以解决跨域的问题。
方法2: 在网关处新增配置类:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.reactive.CorsWebFilter; import org.springframework.web.util.pattern.PathPatternParser;
/** * 跨域允许
*/ @Configuration public class CorsConfig { @Bean public CorsWebFilter corsFilter() { 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");
config.addAllowedMethod("PUT");
config.addAllowedMethod("POST");
config.addAllowedMethod("DELETE");
config.addAllowedMethod("PATCH");
org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource source =
new org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource(new PathPatternParser());
source.registerCorsConfiguration("/**", config);
return new CorsWebFilter(source);
\}
} 可以解决跨域问题。
记录@CrossOrigin发生的问题 在各个微服务对应的Controller,在微服务的Controller中,一般会加上注解@CrossOrigin 当在网关处已经配置了跨域解决时,此时前端会提示:but only one is allowed. 即:重复处理跨域请求 因此只需要去掉这个@CrossOrigin即可
SpringCloud网关Gateway跨域处理,兼容IE 发布于2021-04-22 15:29:15阅读 7170 原文地址:https://www.aiprose.com/blog/139
跨域是一个前后端分离开发无法避免的坑,尤其是要兼容ie。之前单项目的时候,都是在后台直接配置cors就好了,或者在nginx中配置,但是微服务要是挨个都配置,代码量大,也不是很优雅。所以我们一般都会在网关配置跨域处理,以下是我的方案,项目亲测可用。
springboot版本:2.3.9.RELEASE
@Configuration 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(); if (!CorsUtils.isCorsRequest(request)) { return chain.filter(ctx); } String path = request.getPath().value(); ServerHttpResponse response = ctx.getResponse(); if ("/favicon.ico".equals(path)) { response.setStatusCode(HttpStatus.OK); return Mono.empty(); } HttpHeaders requestHeaders = request.getHeaders(); HttpMethod requestMethod = requestHeaders.getAccessControlRequestMethod(); HttpHeaders headers = response.getHeaders(); headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, requestHeaders.getOrigin()); if (requestMethod != null) { headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, requestHeaders.getAccessControlRequestHeaders().toString().replace("[", "").replace("]", "")); 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); } } 复制 一些注意事项: 1.设置ACCESS_CONTROL_ALLOW_HEADERS的时候不能把请求的数组AccessControlRequestHeaders直接给塞进去,否则ie会报错,这里需要转成String类型。 2.OPTION请求过来的时候会带着AccessControlRequestHeaders,我们在OPTION返回的时候设置跨域的请求头,下次正式请求过来的时候,就不需要设置了,因为OPTION预检验是通过的。 3.ACCESS_CONTROL_ALLOW_HEADERS设置*的话,ie上是会报错的。报错异常信息为:Access-Control-Allow-Headers 列表中不存在请求标头 x-requested-with。 4.如果发现设置的跨域响应头是重复的,那么你需要去重,代码在下方。
@Component public class CorsResponseHeaderFilter implements GlobalFilter, Ordered {
@Override public int getOrder() { // 指定位于 NettyWriteResponseFilter 处理完响应体后移除重复 CORS 响应头 return NettyWriteResponseFilter.WRITE_RESPONSE_FILTER_ORDER + 1; }
@Override @SuppressWarnings("serial") public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { return chain.filter(exchange).then(Mono.defer(() -> { exchange.getResponse().getHeaders().entrySet().stream() .filter(kv -> (kv.getValue() != null && kv.getValue().size() > 1)) .filter(kv -> (kv.getKey().equals(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN) || kv.getKey().equals(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS))) .forEach(kv -> kv.setValue(new ArrayList<String>() {{ add(kv.getValue().get(0)); }})); return chain.filter(exchange); })); } }
