Spring Boot 3.1登录接口返回200但报CORS错误且响应体丢失
问题解决方案
核心问题分析
- Spring Security与CORS配置优先级冲突:单独通过
WebMvcConfigurer配置的CORS会被Spring Security的过滤器拦截,因为Security过滤器链执行顺序更早,导致前端的CORS请求无法被正确处理。 - Axios请求Content-Type不匹配:前端将JSON对象转为字符串后,错误设置
Content-Type: multipart/form-data,不符合请求体格式,引发解析异常和预检请求问题。 - 自定义响应头未暴露:登录接口返回的Token头未配置暴露规则,浏览器出于安全策略会拦截该头的读取。
具体修复步骤
1. 调整Spring Security的CORS配置
移除原有的CorsConfig类,在SpringSecurityConfig中直接配置CORS(保证Security过滤器链优先处理CORS):
import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.CorsConfigurationSource; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import java.util.Arrays; @Bean SecurityFilterChain filterChain(HttpSecurity http) throws Exception{ http .csrf(csrf -> csrf.disable()) .cors(cors -> cors.configurationSource(corsConfigurationSource())) // 启用Security内置CORS处理 .sessionManagement(management -> management.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .addFilter(new JwtAuthenticationFilter(authenticationConfiguration.getAuthenticationManager())) .addFilter(new JwtValidationFilter(authenticationConfiguration.getAuthenticationManager())) .authorizeHttpRequests((authorizeHttpRequests) -> authorizeHttpRequests.requestMatchers(HttpMethod.POST, "/login") .permitAll() .anyRequest() .authenticated() ); return http.build(); } // 定义CORS配置源 @Bean CorsConfigurationSource corsConfigurationSource() { CorsConfiguration configuration = new CorsConfiguration(); configuration.setAllowedOriginPatterns(Arrays.asList("*")); configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE")); configuration.setAllowedHeaders(Arrays.asList("*")); configuration.setAllowCredentials(true); configuration.setMaxAge(3600L); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", configuration); return source; }
2. 修正Axios请求的Content-Type
前端请求格式与Content-Type不匹配,修改为正确的JSON格式请求:
var data = { username: username, password: password } const response = await axios({ method: "post", url: `${urlLogin}`, data: data // Axios自动序列化对象为JSON,并设置Content-Type为application/json })
若需手动控制,可改为:
const response = await axios({ method: "post", url: `${urlLogin}`, data: JSON.stringify(data), headers: { "Content-Type": "application/json" // 匹配请求体格式 }, })
3. 暴露自定义响应头
在successfulAuthentication方法中添加响应头暴露配置,允许浏览器读取Token头:
@Override protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException { // ... 原有Token生成逻辑 ... response.addHeader(HEADER_AUTHORIZATION, PREFIX_TOKEN + token); // 添加这行,暴露自定义头给前端 response.setHeader("Access-Control-Expose-Headers", HEADER_AUTHORIZATION); // ... 原有响应体设置逻辑 ... }
验证
完成上述修改后,重新启动后端,前端调用/login接口时:
- 浏览器控制台的CORS错误会消失
- 可正常获取响应体中的token、message等数据
- 响应头中的Token也能被前端读取
内容的提问来源于stack exchange,提问作者urrutias
相关产品推荐
相关产品推荐

