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 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日
    浏览(9)
  • 什么是跨域问题 ?Spring MVC 如何解决跨域问题 ?Spring Boot 如何解决跨域问题 ?

    什么是跨域问题 ?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日
    浏览(122)
  • Spring MVC found on classpath, which is incompatible with Spring Cloud Gateway at this time.

    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日
    浏览(20)
  • 关于spring cloud gateway中出现503 Service  Unavailable的问题

    关于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日
    浏览(40)
  • 优化 spring cloud gateway+nacos时服务恢复调用太慢问题

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

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

    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日
    浏览(8)
  • Spring Cloud Gateway 彻底解决Exceeded limit on max bytes to buffer : 262144报错问题

    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日
    浏览(7)
  • spring cloud gateway中出现503 spring cloud gateway中出现503

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

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

    Spring MVC拦截器和跨域请求

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

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

    【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日
    浏览(12)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包