spring cloud gateway 解决跨域的问题

2022-07-02 08:55:27

1. 背景

随着前端三大框架的横空出世,前后端分离已经成为最流行的编程方式,在这种开发方式下衍生出了一系列的问题,比如说:跨域等,今天我们就来讨论一下跨域解决问题。

2.跨域参数的原因

当一个请求url的协议、域名、端口三者之间任意一个与当前页面那么这个请求就是跨域请求。

3.跨域解决方案

跨域解决方案最出名的有两个jsonp,同源策略

jsonp:是利用script标签绕过同源策略,获得一个类似这样的数据,jsonpcallback是页面存在的回调方法,参数就是想得到的json。
同源策略:就是告诉浏览器某些请求的url是和自己在同一台服务器上。

4. gateway 实现跨域

由于jsonp有很多局限性和缺点,我们一般通过设置同源策略来实现跨域,那么spring cloud gateway 如何实现同源策略设置?

4.1 配置 CorsWebFilter

gateway 是采用 spring webflux 作为 web框架,替换了之前的servelet, 关于webflux的简介请看外行人都能看得懂的WebFlux,错过了血亏! , webflux提供了一个
CorsWebFilter 来设置同源策略。

@BeanpublicCorsWebFiltercorsWebFilter(){UrlBasedCorsConfigurationSource source=newUrlBasedCorsConfigurationSource();CorsConfiguration corsConfiguration=newCorsConfiguration();

        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedMethod("*");
        corsConfiguration.addAllowedOrigin("*");
        corsConfiguration.setAllowCredentials(true);
        corsConfiguration.setMaxAge(600L);

        source.registerCorsConfiguration("/**", corsConfiguration);returnnewCorsWebFilter(source);}

但是我们配置了这个还远远达不到我们的要求,因为它会发生如下错误:
在这里插入图片描述
在这里插入图片描述
打开详情说明我们会惊讶的发现在response header里面出现了多个Access-Control-Allow-Credentials等相关信息。
找到了原因之后我们就需要写一个去重的过滤器。

4.2 写 CorsResponseHeaderFilter类

创建 CorsResponseHeaderFilter 需要继承 GlobalFilter 类, 关于 GlobalFilter 的详解请查看Spring Cloud Gateway(十一):全局过滤器GlobalFilter, CorsResponseHeaderFilter的代码如下:

importcom.flow.utils.JsonUtils;importlombok.extern.slf4j.Slf4j;importorg.springframework.cloud.gateway.filter.GatewayFilterChain;importorg.springframework.cloud.gateway.filter.GlobalFilter;importorg.springframework.cloud.gateway.filter.NettyWriteResponseFilter;importorg.springframework.core.Ordered;importorg.springframework.http.HttpHeaders;importorg.springframework.web.server.ServerWebExchange;importreactor.core.publisher.Mono;importjava.util.ArrayList;@Slf4jpublicclassCorsResponseHeaderFilterimplementsGlobalFilter,Ordered{@OverridepublicintgetOrder(){// 指定此过滤器位于NettyWriteResponseFilter之后// 即待处理完响应体后接着处理响应头returnNettyWriteResponseFilter.WRITE_RESPONSE_FILTER_ORDER+1;}@OverridepublicMono<Void>filter(ServerWebExchange exchange,GatewayFilterChain chain){return chain.filter(exchange).then(Mono.defer(()->{
            exchange.getResponse().beforeCommit(()->{
                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(newArrayList<String>(){{add(kv.getValue().get(0));}});});


                log.info("处理后的数据:{}",JsonUtils.objectToString(exchange.getResponse().getHeaders().entrySet()));return chain.filter(exchange);});return chain.filter(exchange);}));}}

注意: webflux的response类是 ReactorServerHttpResponse,这个类是有为提交和已提交的状态,我们如果需要修改response的内容需要在未提交的状态下修改,所以我们必须要调用beforeCommit 函数来修改。

4.3 配置 CorsResponseHeaderFilter 类

@BeanpublicCorsResponseHeaderFiltercorsResponseHeaderFilter(){returnnewCorsResponseHeaderFilter();}

这样就大功告成了, 来看看运行效果吧
在这里插入图片描述

  • 作者:小星星1991
  • 原文链接:https://blog.csdn.net/qq_21134059/article/details/121808025
    更新时间:2022-07-02 08:55:27