前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SpringCloud网关Gateway跨域处理,兼容IE

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

作者头像
码农笔录
发布2022-05-09 09:34:16
4290
发布2022-05-09 09:34:16
举报
文章被收录于专栏:码农笔录码农笔录

原文地址:https://www.aiprose.com/blog/139

跨域是一个前后端分离开发无法避免的坑,尤其是要兼容ie。之前单项目的时候,都是在后台直接配置cors就好了,或者在nginx中配置,但是微服务要是挨个都配置,代码量大,也不是很优雅。所以我们一般都会在网关配置跨域处理,以下是我的方案,项目亲测可用。

springboot版本:2.3.9.RELEASE

代码语言:javascript
复制
@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.如果发现设置的跨域响应头是重复的,那么你需要去重,代码在下方。

代码语言:javascript
复制
@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);
        }));
    }
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2021-04-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档