gateway跨域,要么跨域问题,要么双重跨域

项目场景:

spring-boot-starter-parent:2.7.6
spring-cloud-alibaba-dependencies:2021.0.1.0


问题描述

使用人人开源快速开发后台管理页面的时候产生了跨域问题,按照以往的经验,在gateway中添加配置类即可,但是在这次发现无效,最终还是产生了跨域问题。

@Configuration
public class CorsConfig {
    @Bean
    public CorsFilter corsFilter() {
        final UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
        final CorsConfiguration corsConfiguration = new CorsConfiguration();
        /*是否允许请求带有验证信息*/
        corsConfiguration.setAllowCredentials(true);
        /*允许访问的客户端域名*/
        corsConfiguration.addAllowedOrigin("*");
        /*corsConfiguration.addAllowedOriginPattern("*");*/
        /*允许服务端访问的客户端请求头*/
        corsConfiguration.addAllowedHeader("*");
        /*允许访问的方法名,GET POST等*/
        corsConfiguration.addAllowedMethod("*");
        urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
        return new CorsFilter(urlBasedCorsConfigurationSource);
    }
}

明明以前使用这个配置类的时候是没有问题的,是可以解决跨域问题的,但是这次同样的操作却失败了,之后再网上找了很久,各种解决跨域的方法都试过了


尝试过程:

WebMvcConfigurer需要导入web包,gateway使用的webflux,GG

@Configuration
public class CorsConfig implements WebMvcConfigurer {
    @Bean
    public WebMvcConfigurer corsConfigurer()
    {
        return new WebMvcConfigurer() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**").
                        allowedOrigins("*"). 
                        allowedMethods("*"). //允许任何方法(post、get等)
		                allowedHeaders("*"). //允许任何请求头
                        allowCredentials(true). //带上cookie信息
                        exposedHeaders(HttpHeaders.SET_COOKIE).maxAge(3600L); //maxAge(3600)
            }
        };
    }
}

原文
有人说是因为过滤器的执行顺序的问题,比如jwt过滤器在CorsFilter前面,所以在进行跨域处理之前,OPTIONS请求就被拒绝了,因为还不知道具体要怎么调试来查看一个请求在gateway的处理方式,所以我的问题到底是不是这个原因还不知道,而且最终这个方法不适合我,GG

产生的问题:

  1. 找不到javax.servlet.Filter的类文件
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
        </dependency>
  1. 报错无法启动
    • Error creating bean with name ‘corsFilter’ defined in class path resource [class]: Post-processing of merged bean definition failed;
    • Failed to introspect Class [] from ClassLoader []
    • NoClassDefFoundError: javax/servlet/FilterRegistration$Dynamic
    • ClassNotFoundException: javax.servlet.FilterRegistration$Dynamic
@Configuration
public class CorsConfig {
	@Bean
    public FilterRegistrationBean corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);
        // 使用setAllowedOrigin会出现IllegalArgumentException
        config.addAllowedOriginPattern("*");
        config.addAllowedHeader("*");
        config.addAllowedMethod("*");
        source.registerCorsConfiguration("/**", config);
        FilterRegistrationBean<CorsFilter> bean = new FilterRegistrationBean<CorsFilter>(new CorsFilter(source));
        //设置优先级
        bean.setOrder(0);
        return bean;
    }
}

原文
后来在网上找到了有关gateway的跨域解决,虽然解决了跨域问题,但是很不幸,产生了双重跨域问题,但是其他地方并没有处理跨域,不知道是什么情况
之前使用nginx的时候也产生过类似的问题,使用oss的时候也会这样,只要携带了图片信息就会产生跨域问题,明明之前的所有服务都可以正常运行,网上说要设置nginx的运行传输内容大小,但是还是没用,最终nginx的问题也没有解决
不过至少跨域问题解决了,就是不知道哪里出现了双重跨域

@Configuration
public class GlobalCorsConfig {
    @Bean
    public WebFilter corsFilter() {
        return (ServerWebExchange ctx, WebFilterChain chain) -> {
            ServerHttpRequest request = ctx.getRequest();
            if (CorsUtils.isCorsRequest(request)) {
                HttpHeaders requestHeaders = request.getHeaders();
                ServerHttpResponse response = ctx.getResponse();
                HttpMethod requestMethod = requestHeaders.getAccessControlRequestMethod();
                HttpHeaders headers = response.getHeaders();
                headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, requestHeaders.getOrigin());
                headers.addAll(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS,
                        requestHeaders.getAccessControlRequestHeaders());
                if (requestMethod != null) {
                    headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, requestMethod.name());
                }
                headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
                headers.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, "*");
                if (request.getMethod() == HttpMethod.OPTIONS) {
                    response.setStatusCode(HttpStatus.OK);
                    return Mono.empty();
                }
            }
            return chain.filter(ctx);
        };
    }
}

原文
后来又发现了一个新奇的东西,通过在gateway中的配置文件解决跨域,但是还是没有用

spring:
  cloud:
    gateway:
      # gateway的全局跨域请求配置
      globalcors:
        corsConfigurations:
          '[/**]':
            allowedHeaders: "*"
            allowedOrigins: "*"
            allowCredentials: true
            allowedMethods: "*"

后来发现了该作者本身也出现了双重跨域问题,解决方法就是去除重复的请求头

spring:
  cloud:
    gateway:
      default-filters:
      - DedupeResponseHeader=Access-Control-Allow-Origin Access-Control-Allow-Credentials Vary, RETAIN_UNIQUE

原因分析:

还没搞懂这是为什么,也许是版本问题?


解决方案:

最终使用了两个方案的结合体,勉强解决了问题

在gateway中创建配置类,虽然解决了跨域问题,但是产生了双重跨域

@Configuration
public class GlobalCorsConfig {
    @Bean
    public WebFilter corsFilter() {
        return (ServerWebExchange ctx, WebFilterChain chain) -> {
            ServerHttpRequest request = ctx.getRequest();
            if (CorsUtils.isCorsRequest(request)) {
                HttpHeaders requestHeaders = request.getHeaders();
                ServerHttpResponse response = ctx.getResponse();
                HttpMethod requestMethod = requestHeaders.getAccessControlRequestMethod();
                HttpHeaders headers = response.getHeaders();
                headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, requestHeaders.getOrigin());
                headers.addAll(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS,
                        requestHeaders.getAccessControlRequestHeaders());
                if (requestMethod != null) {
                    headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, requestMethod.name());
                }
                headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
                headers.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, "*");
                if (request.getMethod() == HttpMethod.OPTIONS) {
                    response.setStatusCode(HttpStatus.OK);
                    return Mono.empty();
                }
            }
            return chain.filter(ctx);
        };
    }
}

在gateway中使用配置文件剔除重复响应头信息,解决双重跨域

spring:
  cloud:
    gateway:
      default-filters:
      - DedupeResponseHeader=Access-Control-Allow-Origin Access-Control-Allow-Credentials Vary, RETAIN_UNIQUE

完成这两个修改后,至少我是解决了我的跨域问题

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
对于Spring Cloud Gateway跨域问题,你可以通过以下步骤解决: 1. 在你的Spring Cloud Gateway项目中,创建一个全局的跨域配置类,比如命名为CorsConfig。 2. 在CorsConfig类上添加注解`@Configuration`,使其成为一个配置类。 3. 在CorsConfig类中添加一个方法来配置跨域规则,比如命名为addCorsMappings。 4. 在addCorsMappings方法上添加注解`@Bean`,使其成为一个Bean。 5. 在addCorsMappings方法中使用CorsRegistry对象来配置跨域规则。例如: ```java @Configuration public class CorsConfig { @Bean public WebFluxConfigurer corsConfigurer() { return new WebFluxConfigurer() { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("*") .allowedMethods("*") .allowedHeaders("*") .exposedHeaders("Authorization") .allowCredentials(true) .maxAge(3600); } }; } } ``` 在上述示例中,通过调用CorsRegistry对象的addMapping方法来添加跨域规则。其中,allowedOrigins设置允许的源(域)地址,allowedMethods设置允许的HTTP方法,allowedHeaders设置允许的请求头,exposedHeaders设置允许暴露的响应头,allowCredentials设置是否允许发送cookie信息,maxAge设置预检请求的缓存时间。 这样配置后,Spring Cloud Gateway就会支持跨域请求了。注意,如果你使用的是WebFlux框架,需要返回WebFluxConfigurer对象并重写addCorsMappings方法;如果使用的是WebMvc框架,则需要返回WebMvcConfigurer对象并重写addCorsMappings方法。 希望以上信息对你有所帮助!如有更多问题,请继续提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值