You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

添加@RefreshScope导致跨域FilterRegistrationBean失效求助

问题:添加@RefreshScope后跨域配置失效且无法实时刷新

原本正常的跨域配置,为实现配置实时刷新给配置类添加@RefreshScope注解后,不仅无法触发配置刷新,还导致跨域完全失效。前端访问接口时出现以下错误:

has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

初始有效跨域配置代码

@Slf4j
@Configuration
public class FilterConfiguration {
    @Value("${jlpay.business.filter.allowCredentials:true}")
    private boolean allowCredentials;
    @Value("${jlpay.business.filter.allowedHeader:*}")
    private String allowedHeader;
    @Value("${jlpay.business.filter.allowedMethod:*}")
    private String allowedMethod;
    @Value("${jlpay.business.filter.allowedOrigin:*}")
    private String allowedOrigin;
    @Value("${jlpay.business.filter.corsPath:/**}")
    private String corsPath;

    /**
     * 跨域请求配置
     * @return
     */
    private CorsConfiguration buildCorsConfig() {
        CorsConfiguration corsConfig = new CorsConfiguration();
        corsConfig.setAllowCredentials(allowCredentials);
        corsConfig.addAllowedHeader(allowedHeader);
        corsConfig.addAllowedMethod(allowedMethod);
        //指定域名拦截配置
        if (!StringUtils.isEmpty(allowedOrigin) && !CorsConfiguration.ALL.equals(allowedOrigin)) {
            String[] originArr = allowedOrigin.split(",");
            for (String origin : originArr) {
                corsConfig.addAllowedOrigin(origin);
            }
        } else {
            corsConfig.addAllowedOrigin(CorsConfiguration.ALL);
        }

        return corsConfig;
    }

    /**
     * 跨域请求过滤器配置
     */
    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
        //注:暂定所有接口均允许跨域,建议针对具体接口配置允许跨域
        configSource.registerCorsConfiguration(corsPath, buildCorsConfig());

        log.info("跨域请求过滤器配置:{}", JSONObject.toJSONString(configSource.getCorsConfigurations()));
        return new CorsFilter(configSource);
    }

    /**
     * 跨域请求配置注册至过滤器
     * @return
     */
    @Bean
    public FilterRegistrationBean corsFilterRegist() {
        FilterRegistrationBean filterRegistration = new FilterRegistrationBean();
        filterRegistration.setFilter(corsFilter());
        filterRegistration.setName("corsFilter");
        filterRegistration.setOrder(0);
        return filterRegistration;
    }
}

添加@RefreshScope后的配置代码

@Slf4j
@Configuration
@RefreshScope
public class FilterConfiguration {
    @Value("${jlpay.business.filter.allowCredentials:true}")
    private boolean allowCredentials;
    @Value("${jlpay.business.filter.allowedHeader:*}")
    private String allowedHeader;
    @Value("${jlpay.business.filter.allowedMethod:*}")
    private String allowedMethod;
    @Value("${jlpay.business.filter.allowedOrigin:*}")
    private String allowedOrigin;
    @Value("${jlpay.business.filter.corsPath:/**}")
    private String corsPath;

    /**
     * 跨域请求配置
     * @return
     */
    private CorsConfiguration buildCorsConfig() {
        CorsConfiguration corsConfig = new CorsConfiguration();
        corsConfig.setAllowCredentials(allowCredentials);
        corsConfig.addAllowedHeader(allowedHeader);
        corsConfig.addAllowedMethod(allowedMethod);
        //指定域名拦截配置
        if (!StringUtils.isEmpty(allowedOrigin) && !CorsConfiguration.ALL.equals(allowedOrigin)) {
            String[] originArr = allowedOrigin.split(",");
            for (String origin : originArr) {
                corsConfig.addAllowedOrigin(origin);
            }
        } else {
            corsConfig.addAllowedOrigin(CorsConfiguration.ALL);
        }

        return corsConfig;
    }

    /**
     * 跨域请求过滤器配置
     */
    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
        //注:暂定所有接口均允许跨域,建议针对具体接口配置允许跨域
        configSource.registerCorsConfiguration(corsPath, buildCorsConfig());

        log.info("跨域请求过滤器配置:{}", JSONObject.toJSONString(configSource.getCorsConfigurations()));
        return new CorsFilter(configSource);
    }

    /**
     * 跨域请求配置注册至过滤器
     * @return
     */
    @Bean
    @RefreshScope
    public FilterRegistrationBean corsFilterRegist() {
        FilterRegistrationBean filterRegistration = new FilterRegistrationBean();
        filterRegistration.setFilter(corsFilter());
        filterRegistration.setName("corsFilter");
        filterRegistration.setOrder(0);
        return filterRegistration;
    }
}

问题原因

  1. @RefreshScope作用于Configuration类的冲突:将@RefreshScope直接加在@Configuration类上,会导致该类生成的所有Bean都被代理,而过滤器的注册逻辑依赖容器的Bean生命周期,代理后的Bean无法被正确识别为过滤器,导致跨域配置不生效。
  2. 重复@RefreshScope导致实例不一致:在FilterRegistrationBean的@Bean方法上重复添加@RefreshScope,会导致过滤器实例和配置实例分离,刷新时无法同步更新过滤器链中的实例。

解决方案

步骤1:抽离配置属性类

将跨域相关配置抽成独立类,用@ConfigurationProperties绑定配置前缀,仅给这个类加@RefreshScope实现属性实时刷新。

@Data
@ConfigurationProperties(prefix = "jlpay.business.filter")
@RefreshScope
public class CorsProperties {
    private boolean allowCredentials = true;
    private String allowedHeader = "*";
    private String allowedMethod = "*";
    private String allowedOrigin = "*";
    private String corsPath = "/**";
}

步骤2:修改FilterConfiguration

去掉Configuration类上的@RefreshScope,通过构造注入CorsProperties,并给CorsFilter的@Bean方法加@RefreshScope确保配置变化时重建过滤器。

@Slf4j
@Configuration
@EnableConfigurationProperties(CorsProperties.class)
public class FilterConfiguration {

    private final CorsProperties corsProperties;

    public FilterConfiguration(CorsProperties corsProperties) {
        this.corsProperties = corsProperties;
    }

    private CorsConfiguration buildCorsConfig() {
        CorsConfiguration corsConfig = new CorsConfiguration();
        corsConfig.setAllowCredentials(corsProperties.isAllowCredentials());
        corsConfig.addAllowedHeader(corsProperties.getAllowedHeader());
        corsConfig.addAllowedMethod(corsProperties.getAllowedMethod());
        
        String allowedOrigin = corsProperties.getAllowedOrigin();
        if (!StringUtils.isEmpty(allowedOrigin) && !CorsConfiguration.ALL.equals(allowedOrigin)) {
            String[] originArr = allowedOrigin.split(",");
            for (String origin : originArr) {
                corsConfig.addAllowedOrigin(origin);
            }
        } else {
            corsConfig.addAllowedOrigin(CorsConfiguration.ALL);
        }
        return corsConfig;
    }

    @Bean
    @RefreshScope
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
        configSource.registerCorsConfiguration(corsProperties.getCorsPath(), buildCorsConfig());
        
        log.info("跨域请求过滤器配置:{}", JSONObject.toJSONString(configSource.getCorsConfigurations()));
        return new CorsFilter(configSource);
    }

    @Bean
    public FilterRegistrationBean corsFilterRegist() {
        FilterRegistrationBean filterRegistration = new FilterRegistrationBean();
        filterRegistration.setFilter(corsFilter());
        filterRegistration.setName("corsFilter");
        filterRegistration.setOrder(0);
        return filterRegistration;
    }
}

步骤3:验证配置刷新

  1. 确保项目已引入Spring Cloud Config相关依赖(若使用自动刷新机制)。
  2. 配置/actuator/refresh端点(需开启Actuator),修改配置后通过POST请求触发刷新。
  3. 查看日志确认配置已更新,再测试前端跨域请求是否恢复正常。

内容的提问来源于stack exchange,提问作者tao zheng

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 11:38:08