React应用首次登录后访问授权路由报错,刷新后恢复正常
排查思路与解决方案
问题根源定位
你的核心问题出在axios实例的Authorization头初始化时机错误:
- 模块加载时(
npm start启动应用阶段)就执行了axiosInstance.defaults.headers.common.Authorization = \Bearer ${localStorage.getItem("tokenKey")}`,此时localStorage里还没有登录后的token,所以这个头的值是Bearer null或Bearer undefined`,属于无效授权信息。 - 登录成功后,你只是把token存入localStorage,但已创建好的axios实例不会自动同步这个变化,导致第一次点击授权菜单时,请求携带的是无效的Authorization头,被Spring Security拦截返回未认证错误。
- 刷新页面后,模块重新加载,此时localStorage里已有token,axios实例初始化时能读取到正确值,请求自然正常。
验证方法
- 登录成功后,在浏览器控制台执行
console.log(axiosInstance.defaults.headers.common.Authorization),查看输出是否为有效token格式,大概率会显示Bearer null。 - 打开浏览器开发者工具的「网络」面板,对比第一次点击菜单和刷新后点击菜单的请求头,观察
Authorization字段的差异。
修复方案
方案1:每次请求前动态更新token
修改getWithAuth方法,每次发起请求时从localStorage读取最新token:
export const getWithAuth = (url) => { const token = localStorage.getItem("tokenKey"); // 仅当token存在时设置授权头 if (token) { axiosInstance.defaults.headers.common.Authorization = `Bearer ${token}`; } else { // 无token时移除授权头,避免无效请求 delete axiosInstance.defaults.headers.common.Authorization; } const request = axiosInstance.get(url); return request.then((response) => response.data); };
方案2:使用axios请求拦截器(更优雅)
给axios实例添加请求拦截器,自动在每次请求前注入最新token,无需在每个请求方法里重复处理:
import axios from "./axios"; const headers = { Accept: "application/json", "Content-Type": "application/json", }; const axiosInstance = axios.create({ headers, }); // 添加请求拦截器 axiosInstance.interceptors.request.use( (config) => { const token = localStorage.getItem("tokenKey"); if (token) { config.headers.Authorization = `Bearer ${token}`; } return config; }, (error) => { return Promise.reject(error); } ); export default axiosInstance; export const getWithAuth = (url) => { const request = axiosInstance.get(url); return request.then((response) => response.data); };
额外排查点
- 确认登录时存入localStorage的token键名确实是
tokenKey,和读取时的键名完全一致。 - 检查是否有其他代码逻辑覆盖了axios实例的Authorization头。
- 虽然Postman请求正常,但可以再确认一次Spring Security的JWT解析配置(比如过滤器顺序、token签名密钥等),排除后端偶发问题。
内容的提问来源于stack exchange,提问作者Jack
相关产品推荐
相关产品推荐

