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的类文件
        
            javax.servlet
            servlet-api
            2.5
        
  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

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

你可能感兴趣的:(我的问题,gateway,servlet,java)