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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 10:21:39