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

React中Axios请求头JWT未更新 需手动重载页面问题

问题表现

登录流程中拿到新JWT令牌写入localStorage、更新Axios默认请求头后,通过React Router跳转到首页,首页加载时自动发起的POST请求携带的仍是旧令牌,只有手动刷新整个页面后,请求才会携带新令牌。
相关代码:

登录页逻辑(login.tsx)

// ...
const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
  event.preventDefault();
  const data = new FormData(event.currentTarget);

  axiosInstance
      .post('token/', {
          username: data.get('username'),
          password: data.get('password'),
      })
      .then((res) => {
          localStorage.setItem('access_token', res.data.access)
          localStorage.setItem('refresh_token', res.data.refresh)
          axiosInstance.defaults.headers.common['Authorization'] = 'JWT ' + localStorage.getItem('access_token')
          navigate('/', { replace: true })
      })
}
// ...

首页逻辑(home.tsx)

// ...
const updateData = () => {
  return axiosInstance.post(`words/update/`, {
    'timezone': Intl.DateTimeFormat().resolvedOptions().timeZone
  })
}

useEffect(() => {
  updateData()
}, [])
// ...

路由配置(App.tsx)

import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import AddWord from "./components/addWord";
import './App.css';
import Home from "./components/home";
import SignIn from "./components/signIn";
import SignUp from "./components/signUp";

function App() {
  return (
    <div className="container">
      <Router>
        <Routes>
          <Route path="/" element={<Home />} />
          <Route path="/add_word" element={<AddWord />} />
          <Route path="/login" element={<SignIn />} />
          <Route path="/register" element={<SignUp />} />
        </Routes>
      </Router>
    </div>
  );
}

export default App;
问题原因

直接修改axiosInstance.defaults.headers的令牌注入方式,在React Router客户端路由跳转场景下存在时序差:路由跳转触发Home组件挂载、useEffect内请求发起的时机,早于登录接口回调中defaults配置的生效时机,导致请求发出时读取到的还是Axios实例初始化时加载的旧令牌。手动刷新页面时,整个应用会重新初始化,Axios实例会重新读取localStorage里的新令牌,所以刷新后请求正常。
这种手动修改默认配置的方式本身也存在维护隐患,后续做令牌静默刷新时也很容易出现令牌不同步的问题。

修复方案

放弃手动修改Axios默认请求头的做法,改用Axios请求拦截器,每次请求发起前实时从localStorage读取最新令牌注入请求头,从根源上避免时序和不同步问题。

  1. 修改Axios实例定义文件,添加请求拦截器:
import axios from 'axios';

const axiosInstance = axios.create({
  // 保留项目原有配置,比如baseURL、timeout等即可
  baseURL: '/api',
});

// 新增请求拦截器
axiosInstance.interceptors.request.use((config) => {
  const accessToken = localStorage.getItem('access_token');
  if (accessToken) {
    config.headers.Authorization = `JWT ${accessToken}`;
  }
  return config;
});

export default axiosInstance;
  1. 删除login.tsx中手动更新Axios默认请求头的代码,修改后登录成功回调如下:
.then((res) => {
    localStorage.setItem('access_token', res.data.access)
    localStorage.setItem('refresh_token', res.data.refresh)
    // 删除原手动修改请求头的代码行
    navigate('/', { replace: true })
})

修改完成后,所有通过该实例发出的请求,都会在发起瞬间读取localStorage中存储的最新令牌,不管是登录跳转还是后续令牌刷新,都不会再出现携带旧令牌的问题,无需手动刷新页面。

内容的提问来源于stack exchange,提问作者João Queiroz

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 08:33:10