Angular调用Spring Boot接口时HttpRequest携带JWT请求头为空问题
问题修复方案
这个问题90%以上的场景是跨域预检(CORS)配置缺失叠加前端请求头构造不规范导致的,Postman可正常访问是因为Postman不受浏览器CORS安全策略限制,不会自动发送预检请求。
优先排查后端CORS配置
浏览器在发送跨域请求时,只要请求带了Authorization这类自定义头,会先自动发送一个OPTIONS方法的预检请求,你在开发者工具里看到的HttpHeaders内部Map大小为0的请求,大概率就是这个预检请求——如果预检没通过,浏览器会直接拦截自定义头,不会把实际请求的头发给后端。
如果你在Spring Boot中集成了Spring Security,必须同时配置CORS规则和Security放行规则,缺一不可:
- 配置全局CORS跨域规则,放开OPTIONS方法、允许并暴露Authorization头:
@Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") // 本地开发放开Angular默认端口,生产环境替换为前端实际部署域名 .allowedOriginPatterns("http://localhost:4200") .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") .allowedHeaders("*") .exposedHeaders("Authorization") .allowCredentials(true) .maxAge(3600); } }
- 在Spring Security配置中放行所有OPTIONS预检请求,避免预检请求被权限拦截器拦下返回401:
@Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .cors().and() .csrf().disable() .authorizeHttpRequests(auth -> auth // 核心规则:放行所有OPTIONS预检请求 .requestMatchers(HttpMethod.OPTIONS, "/**").permitAll() // 其余接口权限规则按实际业务配置即可 .anyRequest().authenticated() ); return http.build(); }
修正Angular端请求头写法
Angular的HttpClient要求传入的headers必须是HttpHeaders类实例,直接传普通对象在部分版本/严格模式下不会被正确解析,会导致头丢失,修正后的代码如下:
import { HttpHeaders } from '@angular/common/http'; greetingFunc() { const token = sessionStorage.getItem("token"); // 提前做token判空,避免传入null/undefined无效值 if (!token) { console.error("登录态失效,请重新登录"); return; } // 显式构造HttpHeaders实例,JWT标准格式需要加Bearer 前缀,后端无特殊要求不要省略 const reqHeaders = new HttpHeaders({ 'Authorization': `Bearer ${token}` }); this.httpClient.get<string>("http://localhost:8080/greeting", { headers: reqHeaders }).subscribe({ next: (res) => { console.log("接口返回:", res); }, error: (err) => { console.error("请求失败:", err); } }); }
如果你用全局拦截器统一注入token,注意Angular的HttpRequest是不可变对象,必须通过clone()方法修改请求头,直接修改原请求的headers属性不会生效。
拦截器正确写法参考:
intercept(req: HttpRequest<any>, next: HttpHandler) { const token = sessionStorage.getItem("token"); if (token) { const authReq = req.clone({ headers: req.headers.set('Authorization', `Bearer ${token}`) }); return next.handle(authReq); } return next.handle(req); }
验证步骤
- 重启后端服务,清空浏览器缓存后重新发起请求
- 打开浏览器开发者工具Network面板,先确认OPTIONS请求返回200状态码,响应头包含
Access-Control-Allow-Headers: Authorization - 再查看同路径下的GET请求,即可在请求头中看到正常携带的Authorization字段,后端调用
request.getHeader("Authorization")即可正常获取到token值
内容的提问来源于stack exchange,提问作者Filip_k_island
相关产品推荐
相关产品推荐

