Spring Cloud Gateway 、 Spring MVC 联合跨域问题和遇到的坑

这篇具有很好参考价值的文章主要介绍了Spring Cloud Gateway 、 Spring MVC 联合跨域问题和遇到的坑。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

遇到问题

此问题网上很多解决方案,其实各个都没有错,各个解决方案都是正确,但是分类成好几个类型统一引起的,把网上的中解决方案在放在一起,就会出现不但不可以解决问题,反而更加引起混乱,明明已经正确按不同方法实现了一遍,就是不行


问题分类

(1)spring mvc 单独跨域问题

(2)gateway 单独跨域问题

(3)gateway + spring mvc 后端联合跨域问题


一、spring mvc 单独跨域问题

此问题最简单,添加mvc 过滤器就可以了

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CORSFilter implements Filter {
  Logger logger  = LoggerFactory.getLogger("跨域过滤器");

  @Override
  public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {


    final HttpServletRequest request = (HttpServletRequest) servletRequest;
    final HttpServletResponse response = (HttpServletResponse) servletResponse;
   // final String origin = request.getHeader("Origin");
    Collection<String>  aa = response.getHeaders("Access-Control-Allow-Origin");
    response.setHeader("Access-Control-Allow-Origin", "*");
    Collection<String>  bb = response.getHeaders("Access-Control-Allow-Origin");
    response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
    response.setHeader("Access-Control-Max-Age", "3600");
    response.setHeader("Access-Control-Allow-Headers", "Authorization,authorization_refresh,content-type,_isfresh");
    if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
      response.setStatus(HttpServletResponse.SC_OK);
    //  servletRequest.getRequestDispatcher("/block").forward(servletRequest, servletResponse);
      return;
    } else {
      filterChain.doFilter(request, response);
    }
  }

  /**
   *  可以初始化Filter在web.xml里面配置的初始化参数
   *  filter对象只会创建一次,init方法也只会执行一次。
   * @param filterConfig
   * @throws ServletException
   */
  @Override
  public void init(FilterConfig filterConfig) throws ServletException {
    logger.info("跨域过滤器初始化完成");
  }

  @Override
  public void destroy() {

  }
}

二、gateway 单独单独跨域问题

     所谓单独跨域是指,网关后面的后端,不再对跨域的代码进行一次跨域设置,否则会出错,详细请看 第三节

    这里面有个

注意两个过滤器的不同

CorsWebFilterGlobalFilter , 网上有针对这两种过滤器的【跨域设置代码】,其中亲自尝试GlobalFilter完全没有效果,具体原因是

由于gateway使用的是webflux,而不是springmvc,需要覆盖掉webflux默认的CORS处理配置,通过注册新的CorsWebFilter Bean来解决跨域问题,而且似乎 GlobalFilter 是在 CorsWebFilter 之后执行的,所以

headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, "*");

完全无效,系统进不到过滤器GlobalFilter已经被CorsWebFilter拦截了

具体步骤是在post,get 之前,前端浏览器会预先向发起options 请求,预先访问服务的是否许可,当服务端回复可以访问后,再提交post 或 get进行第二次访问

Spring Cloud Gateway 、 Spring MVC 联合跨域问题和遇到的坑

因此要用 CorsWebFilter 作为过滤器首选,代码如下

@Configuration
public class GwCorsFilter {
    @Bean
    public CorsWebFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());

        //cors跨域配置对象
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.setAllowCredentials(false);//是否允许携带cookie
        // corsConfiguration.addAllowedOriginPattern("*");
        corsConfiguration.addAllowedOrigin("*"); //允许跨域访问的域名,可填写具体域名,*代表允许所有访问
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedMethod("*");
/*
        corsConfiguration.addAllowedMethod(HttpMethod.POST);//允许访问类型:get  post 等,*代表所有类型
        corsConfiguration.addAllowedMethod(HttpMethod.GET);
        corsConfiguration.addAllowedMethod(HttpMethod.HEAD);
        corsConfiguration.addAllowedMethod(HttpMethod.OPTIONS);
        corsConfiguration.addAllowedMethod(HttpMethod.PATCH);
*/
        source.registerCorsConfiguration("/**", corsConfiguration);

        return new CorsWebFilter(source);

    }
}

坑2 

  如果选择

corsConfiguration.setAllowCredentials(true);

参数会出现一下错误

ava.lang.IllegalArgumentException: When allowCredentials is true, allowedOrigins cannot contain the special value "*" since that cannot be set on the "Access-Control-Allow-Origin" response header. To allow credentials to a set of origins, list them explicitly or consider using "allowedOriginPatterns" instead.

at org.springframework.web.cors.CorsConfiguration.validateAllowCredentials(CorsConfiguration.java:473)

Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException:

Error has been observed at the following site(s):

*__checkpoint ⇢ org.springframework.cloud.gateway.filter.WeightCalculatorWebFilter [DefaultWebFilterChain]

*__checkpoint ⇢ com.alibaba.csp.sentinel.adapter.spring.webflux.SentinelWebFluxFilter [DefaultWebFilterChain]

*__checkpoint ⇢ HTTP OPTIONS "/chrisboot/api/v1/NewsLayout/Search_index_VwData?type=1" [ExceptionHandlingWebHandler]

顾名思义,修改以下代码可执行

corsConfiguration.setAllowCredentials(true);//是否允许携带cookie
corsConfiguration.addAllowedOriginPattern("*");
//corsConfiguration.addAllowedOrigin("*"); 

具体不同是 返回前端的参数不同,如图

Spring Cloud Gateway 、 Spring MVC 联合跨域问题和遇到的坑

Spring Cloud Gateway 、 Spring MVC 联合跨域问题和遇到的坑

或者还有其他用途,未进一步尝试,不是主要矛盾,至少我的前端是不需要携带cookie的


三、Spring Cloud Gateway 、 Spring MVC 联合跨域

此问题最坑,耗费大量时间

单独gateway ,单独 web mvc都没问题,两个框架联合起来, 网关 + web 后端 就有问题了!!!

主要问题体现,前端浏览器返回

' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header contains multiple values '*, *', but only one is allowed.

Spring Cloud Gateway 、 Spring MVC 联合跨域问题和遇到的坑

Spring Cloud Gateway 、 Spring MVC 联合跨域问题和遇到的坑

 具体原因是因为 经过了 网关 + 后端web 两层过滤 , 所有参数都变成了2次重复,而 Access-Control-Allow-Origin 只允许一个,造成了错误

既然知道原因了,就寻找解决方案,思路如下

解决方案

2个过滤去掉其中一个

(1)方案一

      去掉 gateway ,保留web mvc过滤器 , 直接网关都进不去了,何况到后端,这种方式pass

 (2) 方案二

     去掉 web mvc 过滤, 只保留 gateway 跨域过滤器, 经过 测试 可行,验证通过

    但是存在一定局限性 , 你只能控制网关, 以后 所有的后端不能再加跨域控制, 如果所有程序是你开发的可以,如果是别人的后端程序,你不一定能控制到代码。

    其二后端程序也有一定需求是要独立运行的,不是全通过网关,这样后端程序不加跨域控制器,也无法独立运行,也不可能要求作者维护两套不同版本。

方案二只能说可以暂时解决问题,但是不完美

(3)方案三

经过测试,gateway + web mvc后端 两个都加过滤器的话,其实是能回到response返回给前端的,只是前端浏览器接收失败的(意思是两个过滤器都执行了,同步加了两套header), 那这样就再动态等它加完两套加完后,再代码删除就好了。

     实施情况1:  删除后端web mvc 情况,先判断 gateway 没有把header传过来,又传过来,就不添加了,或者添加后,执行完过滤器后,再动态把多余的header删除掉

              结果:失败, 因为搞不定在后端侧,读取 gateway 读出的 header ,或者有方法,但是我没找到

   实施情况2:  gateway 过滤器  GlobalFilter 分为前过滤器,后过滤器,再执行完后端后,查找有没有多余的header ,发现有,删除掉

             结果:成功 , 问题彻底解决,代码如下

@Component
public class GlobalCustomFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //前置过滤


        return chain.filter(exchange)
                .then(Mono.fromRunnable(
                        () -> {
                            //后置过滤
                            ServerHttpResponse response = exchange.getResponse();
                            HttpHeaders headers_after = response.getHeaders();
                            if (headers_after.get("Access-Control-Allow-Origin")!=null && headers_after.get("Access-Control-Allow-Origin").size() > 1)
                              headers_after.set("Access-Control-Allow-Origin", "*");
                        }
                ));

        //return chain.filter(exchange);
    }
}

问题彻底解决,只修改网关灵活方便, 后端程序可以保持自己的跨域过滤器

注意 GlobalFilter CorsWebFilter 两个联合使用,一个做后期去掉多余header , 一个作为前期加入第一个header (第二个又后端的mvc再加)文章来源地址https://www.toymoban.com/news/detail-490844.html

到了这里,关于Spring Cloud Gateway 、 Spring MVC 联合跨域问题和遇到的坑的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Spring MVC found on classpath, which is incompatible with Spring Cloud Gateway错误

      原因是因为spring cloud gateway 是建立在spring boot 2.x 和 spring webflux基础上的既:gateway 本身已经包含了spring mvc 的功能,正与提示的一样和spring boot 的web starter冲突了 找到gateway下面的spring-boot-starter-web依赖,然后 将其注释掉  

    2024年02月15日
    浏览(44)
  • 什么是跨域问题 ?Spring MVC 如何解决跨域问题 ?Spring Boot 如何解决跨域问题 ?

    目录 1. 什么是跨域问题 ? 2. Spring MVC 如何解决跨域问题 ? 3. Spring Boot 如何解决跨域问题 ?  跨域问题指的是不同站点之间,使用 ajax 无法相互调用的问题。 跨域问题的 3 种情况: 1. 协议不同,例如 http 和 https; http://127.0.0.1:8080 https://127.0.0.1:8080 2. 域名不同; 一级域名、

    2024年02月10日
    浏览(85)
  • Spring MVC found on classpath, which is incompatible with Spring Cloud Gateway at this time.

    项目概述:  问题解决: 步骤一:在关联的两个模块zx-gateway-0829和zx-common-0829中寻找 spring-boot-starter-web  步骤二:删除gateway模块pom.xml中关联的commont模块,将common中gateway所需要的工具复制一份到gateway模块对应位置下。 嗨喽,CSDN的友友们,今天启动网关Gateway时发现了一个不兼

    2023年04月26日
    浏览(59)
  • 关于spring cloud gateway中出现503 Service Unavailable的问题

    1.引用spring cloud gateway+nacos配置中心 2.微服务+分布式(本节与分布式问题无关)项目 3.路由规则:网关端口:8085;第三方端口:8081,8086 第三方单独访问路径localhost:8081/test/getUserTest?id=2 希望路由到:localhost:consumer-service/test/getUserTest?id=2 (这里我写了两个消费者服务,服务名一致

    2024年02月01日
    浏览(60)
  • 优化 spring cloud gateway+nacos时服务恢复调用太慢问题

    问题描述 在使用 spring cloud gateway + nacos 做服务发现时,会发现当下游的服务器恢复了,但是还有经过一段时间 gateway 才成功转发请求到刚恢复的下游服务上。于是我就深入源码进行企图通过修改相关配置的方式优化gateway服务发现的恢复时间。 相关依赖版本 源码 经过漫长的

    2024年02月01日
    浏览(61)
  • skywalking-agent-java默认不支持spring cloud gateway问题

    开发环境:Windows10 、JDK17 skywalking官网下载地址:https://skywalking.apache.org/downloads/ 解压目录为:D:Programssoft-Pluginsapache-skywalking-java-agent-8.16.0skywalking-agent 解压后目录结构为: 可参考官网博客文档:https://skywalking.apache.org/zh/2020-04-19-skywalking-quick-start/#232-idea 我的IDEA版本: Int

    2024年02月09日
    浏览(47)
  • Spring Cloud Gateway 彻底解决Exceeded limit on max bytes to buffer : 262144报错问题

    使用Spring Cloud Gateway开发内部API网关时,当业务的Http请求体大小超过256K时,会出现如下报错:Exceeded limit on max bytes to buffer : 262144。 Spring Boot框架给了两种方式来修改这个大小的方式: 方式一:使用修改配置参数值,spring.max-in-memory-size: 1024 * 1024 的方式 方式二:使用WebFluxC

    2024年02月10日
    浏览(47)
  • spring cloud gateway中出现503 spring cloud gateway中出现503

    当搭建网关模块的时候出现503的错误的最大的可能就是没有设置负载均衡的依赖包  原先搭建的时候采用的是下面的方式进行设置的 上面的这种方式可以直接进行注册和发现,但是要求必须导入下面的依赖 希望简单的随笔能够帮助你!

    2024年02月11日
    浏览(52)
  • 【Spring Cloud 八】Spring Cloud Gateway网关

    【Spring Cloud一】微服务基本知识 【Spring Cloud 三】Eureka服务注册与服务发现 【Spring Cloud 四】Ribbon负载均衡 【Spring Cloud 五】OpenFeign服务调用 【Spring Cloud 六】Hystrix熔断 【Spring Cloud 七】Sleuth+Zipkin 链路追踪 在项目中是使用了Gateway做统一的请求的入口,以及统一的跨域处理以及

    2024年02月12日
    浏览(48)
  • Spring MVC拦截器和跨域请求

    SpringMVC的拦截器(Interceptor)也是AOP思想的一种实现方式。它与Servlet的过滤器(Filter)功能类似,主要用于拦截用户的请求并做相应的处理,通常应用在权限验证、记录请求信息的日志、判断用户是否登录等功能上。 拦截器和过滤器的区别 拦截器是SpringMVC组件,而过滤器是

    2024年02月16日
    浏览(56)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包