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

Spring Boot 3中PUT请求出现CORS跨域错误求助

问题描述

使用Spring Boot 3.1.6、Spring Security 6.1.5与JDK 17搭建后端服务,已配置CORSConfig类和SecurityConfig中的SecurityFilterChain Bean。通过Postman和服务器端Swagger测试API均正常,但集成React前端后,GET、POST请求可正常调用,PUT请求却出现「No 'Access-Control-Allow-Origin' header is present on the requested resource」错误。

现有配置代码

CORSConfig类

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@EnableWebMvc
public class CORSConfig{

    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurer() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**")
                        .allowedOrigins("*")
                        .allowedMethods("HEAD", "GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS")
                        .allowedHeaders("*")
                        .allowCredentials(false)
                        .maxAge(3600);
            }
        };
    }
}

SecurityConfig中的SecurityFilterChain Bean

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http.csrf(csrf -> csrf.disable())
            .cors(httpSecurityCorsConfigurer ->
                    httpSecurityCorsConfigurer.configurationSource(request ->
                                    new CorsConfiguration().applyPermitDefaultValues()))
            .exceptionHandling(exception -> exception.authenticationEntryPoint(unauthorizedHandler))
            .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
            .authorizeHttpRequests(auth ->
                    auth.requestMatchers("/api/auth/**").permitAll()
                            .requestMatchers("/swagger-ui/**", "/v3/api-docs/**").permitAll()
                            .requestMatchers("/api/test/**").permitAll()
                            .anyRequest().authenticated()
            );

    http.authenticationProvider(authenticationProvider());

    http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);

    return http.build();
}
问题原因

Spring Security的CORS配置优先级高于WebMvc的CORS配置。你在Security中使用new CorsConfiguration().applyPermitDefaultValues()时,这个方法默认仅允许GET、HEAD、POST三种请求方法,不包含PUT。当React前端发起PUT请求时,浏览器会先发送OPTIONS预检请求,此时Security返回的响应没有包含允许PUT的CORS头,导致前端报错。

解决方案

可以通过以下两种方式修复:

方案一:统一使用Security的CORS配置(推荐)

移除CORSConfig类,直接在Security配置中指定完整的CORS规则,确保包含PUT方法:

import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import java.util.Arrays;
import java.util.Collections;

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    // 定义CORS配置
    CorsConfiguration corsConfig = new CorsConfiguration();
    corsConfig.setAllowedOriginPatterns(Collections.singletonList("*")); // Spring Boot 2.4+推荐用此方法替代allowedOrigins
    corsConfig.setAllowedMethods(Arrays.asList("HEAD", "GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"));
    corsConfig.setAllowedHeaders(Collections.singletonList("*"));
    corsConfig.setAllowCredentials(false);
    corsConfig.setMaxAge(3600L);

    // 配置CORS源
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", corsConfig);

    http.csrf(csrf -> csrf.disable())
            .cors(cors -> cors.configurationSource(source)) // 使用自定义CORS配置
            .exceptionHandling(exception -> exception.authenticationEntryPoint(unauthorizedHandler))
            .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
            .authorizeHttpRequests(auth ->
                    auth.requestMatchers("/api/auth/**").permitAll()
                            .requestMatchers("/swagger-ui/**", "/v3/api-docs/**").permitAll()
                            .requestMatchers("/api/test/**").permitAll()
                            .anyRequest().authenticated()
            );

    http.authenticationProvider(authenticationProvider());

    http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);

    return http.build();
}

方案二:让Security复用WebMvc的CORS配置

保留CORSConfig类,修改Security中的CORS配置,使其复用WebMvc的CORS规则:

import org.springframework.web.servlet.config.annotation.CorsRegistry;

@Bean
public SecurityFilterChain filterChain(HttpSecurity http, WebMvcConfigurer webMvcConfigurer) throws Exception {
    http.csrf(csrf -> csrf.disable())
            .cors(cors -> cors.configurationSource(request -> {
                // 从WebMvcConfigurer中提取已配置的CORS规则
                CorsRegistry registry = new CorsRegistry();
                webMvcConfigurer.addCorsMappings(registry);
                return registry.getCorsConfigurations().get("/**");
            }))
            .exceptionHandling(exception -> exception.authenticationEntryPoint(unauthorizedHandler))
            .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
            .authorizeHttpRequests(auth ->
                    auth.requestMatchers("/api/auth/**").permitAll()
                            .requestMatchers("/swagger-ui/**", "/v3/api-docs/**").permitAll()
                            .requestMatchers("/api/test/**").permitAll()
                            .anyRequest().authenticated()
            );

    http.authenticationProvider(authenticationProvider());

    http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);

    return http.build();
}
额外注意事项
  • 如果需要允许携带凭证(allowCredentials(true)),则allowedOrigins不能设为*,必须指定具体的前端域名,比如http://localhost:3000
  • 确保前端发起PUT请求时没有携带未被允许的额外请求头,当前配置allowedHeaders("*")已覆盖此场景

内容的提问来源于stack exchange,提问作者Pushpendra Kushvaha

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 09:05:58