如何从fetch请求的响应头提取Spring Boot接口的JWT令牌并存储?
无法从响应头提取JWT的核心原因
你在浏览器网络面板能看到接口返回的JWT响应头,说明接口本身返回逻辑是正常的,代码读取失败基本是两个共性问题导致:
- 原始fetch代码完全没有接收接口返回的Response对象,不存在读取响应头的执行链路
- 跨域场景下,浏览器默认仅允许前端JS读取6个基础响应头(Cache-Control、Content-Length、Content-Type、Expires、Last-Modified、Pragma),如果后端没有将JWT所在的自定义响应头做CORS暴露配置,哪怕网络面板能看到对应头内容,前端JS也无权读取,
headers.get()会直接返回null。
分步解决流程
1. 配置后端CORS暴露规则(关键步骤)
在Spring Boot的全局跨域配置中,新增exposedHeaders配置,将存放JWT的响应头暴露给前端。参考配置示例:
@Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("你的前端页面实际访问地址,例如http://localhost:5500") .allowedMethods("GET", "POST", "PUT", "DELETE") .allowedHeaders("*") // 关键配置:把JWT所在的响应头加入暴露列表,替换为你实际返回的头名 .exposedHeaders("Authorization", "X-Auth-Token") .allowCredentials(true) .maxAge(3600); } }
注意:很多开发者会混淆allowedHeaders和exposedHeaders的作用:allowedHeaders用于限制前端可以携带的请求头范围,exposedHeaders用于配置前端可以读取的响应头范围,二者不能互相替代。如果你的项目集成了Spring Security,需要在Security对应的CORS配置中通过addExposedHeader()方法添加对应JWT头名即可。
2. 修改前端fetch代码,正确提取并存储JWT
fetch是异步请求,返回Promise对象,必须通过await或者.then()链路拿到Response实例,才能调用headers.get()方法读取对应头值。修改后的可用代码如下:
async function handleLogin() { try { const response = await fetch('http://localhost:8080/login', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ username: 'linda', password: 'password' }) }) // 替换成后端实际返回的JWT头名称,例如Authorization const jwtToken = response.headers.get('Authorization') if (jwtToken) { // 存储到localStorage localStorage.setItem('jwt_token', jwtToken) console.log('JWT存储成功', jwtToken) } else { console.error('未读取到JWT头,请检查后端暴露配置与头名是否匹配') } } catch (error) { console.error('登录请求异常', error) } } // 执行登录逻辑 handleLogin()
常见踩坑排查
- 如果
response.headers.get()返回null,优先核对两个点:一是后端是否真的配置了Access-Control-Expose-Headers规则;二是读取的头名称和后端实际返回的头名是否完全匹配(头名解析不区分大小写,但拼写不能有误) - 不要直接同步获取fetch的返回值,你最初写的代码未做任何返回值捕获,自然无法读取响应头内容
- 注意异步执行顺序,不要在
await拿到请求结果前就读取localStorage中存储的JWT值,否则会拿到空值
内容的提问来源于stack exchange,提问作者Niejadek
相关产品推荐
相关产品推荐

