• Spring Cloud Gateway 2.x 跨域出现The 'Access-Control-Allow-Origin' header contains multiple values,....but only one is allowed 的问题解决


    问题描述:vue前端调用后端登陆接口报错如下

    Access to XMLHttpRequest at 'http://localhost:88/api/sys/login' from origin 'http://localhost:8002' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header contains multiple values 'http://localhost:8002, http://localhost:8002', but only one is allowed.

     原因:spring NettyRoutingFilter 添加了两次Access-Control-Allow-Origin

    解决方案:

    1.新增CorsResponseHeaderFilter.java

    import java.util.ArrayList;
    
    import org.springframework.cloud.gateway.filter.GatewayFilterChain;
    import org.springframework.cloud.gateway.filter.GlobalFilter;
    import org.springframework.cloud.gateway.filter.NettyWriteResponseFilter;
    import org.springframework.core.Ordered;
    import org.springframework.http.HttpHeaders;
    import org.springframework.web.server.ServerWebExchange;/**
     * 跨域请求头处理过滤器扩展
     */
    public class CorsResponseHeaderFilter implements GlobalFilter, Ordered {
        @Override
        public int getOrder() {
            // 指定此过滤器位于NettyWriteResponseFilter之后
            // 即待处理完响应体后接着处理响应头
            return NettyWriteResponseFilter.WRITE_RESPONSE_FILTER_ORDER + 1;
        }
    
        @Override
        @SuppressWarnings("serial")
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            return chain.filter(exchange).then(Mono.defer(() -> {
                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(new ArrayList<String>() {{add(kv.getValue().get(0));}});
                });
                
                return chain.filter(exchange);
            }));
        }
    }

    2.跨域全局配置:CorsConfiguration.java

    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.http.HttpMethod;
    import org.springframework.web.cors.CorsConfiguration;
    import org.springframework.web.cors.reactive.CorsWebFilter;
    import org.springframework.web.cors.reactive.DefaultCorsProcessor;
    import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
    import org.springframework.web.server.ServerWebExchange;
    import org.springframework.web.util.pattern.PathPatternParser;
    
    /**
     * 网关跨域配置
     */
    @Configuration
    public class CorsConfiguration {
        @Bean
        public CorsResponseHeaderFilter corsResponseHeaderFilter() {
            return new CorsResponseHeaderFilter();
        }
        
        @Bean
        public CorsWebFilter corsFilter() {
            UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
            source.registerCorsConfiguration("/**", buildCorsConfiguration());
            
            CorsWebFilter corsWebFilter = new CorsWebFilter(source, new DefaultCorsProcessor() {
                @Override
                protected boolean handleInternal(ServerWebExchange exchange, CorsConfiguration config, 
                    boolean preFlightRequest) 
                {
                    // 预留扩展点
                    // if (exchange.getRequest().getMethod() == HttpMethod.OPTIONS) {
                        return super.handleInternal(exchange, config, preFlightRequest);
                    // }
    
                    // return true;
                }
            });
            
            return corsWebFilter;
        }
        
        private CorsConfiguration buildCorsConfiguration() {
            CorsConfiguration corsConfiguration = new CorsConfiguration();
            corsConfiguration.addAllowedOrigin("*");
            
            corsConfiguration.addAllowedMethod(HttpMethod.OPTIONS);
            corsConfiguration.addAllowedMethod(HttpMethod.POST);
            corsConfiguration.addAllowedMethod(HttpMethod.GET);
            corsConfiguration.addAllowedMethod(HttpMethod.PUT);
            corsConfiguration.addAllowedMethod(HttpMethod.DELETE);
            corsConfiguration.addAllowedMethod(HttpMethod.PATCH);
            // corsConfiguration.addAllowedMethod("*");
    corsConfiguration.addAllowedHeader("*");
            
            corsConfiguration.setMaxAge(7200L);
            corsConfiguration.setAllowCredentials(true);
            return corsConfiguration;
        }
    }
  • 相关阅读:
    git提交代码五部曲
    菜单树jstree.js插件几个主要事件汇总
    创维电视加mac过滤后连不了wifi问题(路由器为TP-link)
    Mysql和Navicat for MySQL本地运行.sql文件
    MySQL下载与安装
    js一个区域拖拽到另一个区域,拖拽后还可以排序。知识点:js插件Jquery-UI:拖拽组件draggable,放置组件droppable,排序组件sortable
    echarts基本应用-更改坐标轴文字样式、轴名称、轴刻度、轴线、轴网格、曲线(折线图)、柱体上面显示值(柱状图),鼠标悬浮提示
    boostrap的时间插件daterangepicker.js之单日期,精确到秒
    echarts用法之点击事件(圆柱体例子)
    注册界面和功能
  • 原文地址:https://www.cnblogs.com/jinjingBlog/p/14339828.html
Copyright © 2020-2023  润新知