SpringCloud网关Gateway跨域处理,兼容IE

11 篇文章 0 订阅
5 篇文章 0 订阅

原文地址: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);
        }));
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农笔录

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值