有时候,我们需要对所有微服务跨域请求进行处理.
跨域的说明:
哪些场景是跨域:不同的系统进行AJAX的请求的时候属于跨域的。 跨域的请求一般是不被允许的。
1.www.jd.com---->www.taobao.com 跨域
2.localhost:8001 —>localhost:8002 跨域
3.www.jd.com:80—>www.jd.com:81 跨域
4.https —>http 跨域。
域名相同,端口相同,协议相同 就不是跨域。
解决跨域的问题的解决方案:
解决方式涉及到图如下:
通过@CrossOrigin()注解实现

如果都需要跨域处理,该方式需要在每一个Controller类上配置。
另外我们一般在SpringCloudGateway网关配置

上图配置信息如下
spring:
cloud:
gateway:
globalcors:
cors-configurations:
'[/**]': # 匹配所有请求
allowedOrigins: "*" #跨域处理 允许所有的域
allowedMethods: # 支持的方法
- GET
- POST
- PUT
- DELETE
前端页面通过不同域名或IP访问SpringCloud Gateway,那么,此时直连微服务和网关的跨域问题都解决了,是不是很完美?
No~ 问题来了,前端仍然会报错:“不允许有多个’Access-Control-Allow-Origin’ CORS头”。
问题:Vary 和 Access-Control-Allow-Origin 两个头重复了两次,其中浏览器对后者有唯一性限制!
解决方式之一:手动写一个 CorsResponseHeaderFilter 的 GlobalFilter 去修改Response中的头。
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.filter.NettyWriteResponseFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
* @Auther: 郑洁文
* @Date: 2022年10月26日 1:10
* @Description:
*/
@Component
public class CorsResponseHeaderFilter implements GlobalFilter, Ordered {
private static final String ANY = "*";
@Override
public int getOrder() {
// 指定此过滤器位于NettyWriteResponseFilter之后
// 即待处理完响应体后接着处理响应头
return NettyWriteResponseFilter.WRITE_RESPONSE_FILTER_ORDER + 1;
}
@Override
@SuppressWarnings("serial")
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
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)
|| kv.getKey().equals(HttpHeaders.VARY)))
.forEach(kv ->
{
// Vary只需要去重即可
if(kv.getKey().equals(HttpHeaders.VARY))
kv.setValue(kv.getValue().stream().distinct().collect(Collectors.toList()));
else{
List<String> value = new ArrayList<>();
if(kv.getValue().contains(ANY)){ //如果包含*,则取*
value.add(ANY);
kv.setValue(value);
}else{
value.add(kv.getValue().get(0)); // 否则默认取第一个
kv.setValue(value);
}
}
});
}));
}
}
基于SpringCloudGateway网关配置完成。