React向Spring Boot后端请求时自定义Header丢失问题求助
我来帮你拆解并解决这个问题,你遇到的是典型的CORS预检请求(OPTIONS)处理不当导致的问题,咱们一步步来梳理:
首先纠正前端的两个关键错误
Access-Control-Allow-Origin是响应头,不是请求头!
你在fetch和axios里给请求加这个头完全没必要,反而会触发浏览器更严格的预检机制——因为自定义请求头会强制浏览器先发送OPTIONS预检请求,这也是后续问题的导火索之一,直接删掉这行配置。Authorization头格式错误
你写的'Bearer' + token少了一个空格,正确格式应该是'Bearer ' + token(Bearer后面必须跟空格),否则后端解析令牌时会失败。
修改后的代码如下:
Fetch版本
fetch('http://127.0.0.1:8080/api/tender', { method: 'GET', headers: { Authorization: 'Bearer ' + token } });
Axios版本
axios.defaults.headers.common['Authorization'] = 'Bearer ' + token; // 删掉这行:axios.defaults.headers.common['Access-Control-Allow-Origin'] = '*'; axios.get('http://127.0.0.1:8080/api/tender').then((res) => console.log(res));
后端Spring Boot的核心配置调整
浏览器发送OPTIONS预检请求时,不会携带Authorization头(这是浏览器的安全机制),所以你的后端必须对OPTIONS请求放行,不能做令牌验证,否则预检失败后,后续的GET请求根本不会被触发。
方案1:全局CORS配置
添加全局CORS配置类,明确允许前端域名、请求方法和自定义请求头:
@Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/api/**") .allowedOrigins("http://localhost:3000") // 明确指定你的前端域名,不要用*(带认证场景下*不生效) .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") .allowedHeaders("Authorization", "Content-Type") // 允许Authorization请求头 .allowCredentials(true) // 如果前端需要携带cookie,开启这个 .maxAge(3600); // 预检请求缓存时长,减少OPTIONS请求次数 } }
方案2:如果用Spring Security,还要额外放行OPTIONS请求
如果你的项目集成了Spring Security,需要在安全配置里单独允许OPTIONS请求通过,不做认证校验:
@Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.cors().and() .authorizeRequests() .antMatchers(HttpMethod.OPTIONS, "/api/**").permitAll() // 放行OPTIONS请求 .anyRequest().authenticated(); // 其他安全配置... } }
为什么手动重发请求能成功?
手动重发GET请求时,浏览器不会触发预检流程(直接发送GET请求),此时你的后端能正常解析Authorization头,所以返回200。但正常前端请求中,因为携带了自定义的Authorization头,浏览器必须先做OPTIONS预检,只有预检请求返回200,才会自动发送后续的GET请求。
按照上面的步骤调整后,就能实现OPTIONS请求返回OK后自动执行GET请求的预期效果了。
内容的提问来源于stack exchange,提问作者Øystein Seel

