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

如何在Axios拦截器中获取Redux存储的Access Token并处理过期?

解决Axios拦截器中获取Redux存储Access Token的方案

下面是几个实用的解决方案,帮你在组件外的Axios拦截器里获取Redux中的Access Token:

方案1:直接导入Redux Store实例

在创建Redux Store的时候,把实例导出,拦截器里直接通过store.getState()读取状态。

步骤:

  1. 在Store配置文件中导出store实例:
// store.js
import { configureStore } from '@reduxjs/toolkit';
import authReducer from './authSlice';

// 导出store实例
export const store = configureStore({
  reducer: {
    auth: authReducer,
  },
});
  1. 在Axios实例文件中导入store,读取token并处理过期逻辑:
import axios from "axios";
import jwtDecode from "jwt-decode"; // 需要安装jwt-decode库
import { store } from './store';
import { setAccessToken } from './authSlice'; // 假设你有更新token的action

const axiosInstance = axios.create({
  baseURL: "http://localhost:5000/api/v1",
});

// 拦截器支持async函数处理异步逻辑
axiosInstance.interceptors.request.use(async (req) => {
  // 从Redux获取token
  const { accessToken } = store.getState().auth;

  if (accessToken) {
    const decodedToken = jwtDecode(accessToken);
    // 检查token是否过期(exp是秒级时间戳,转成毫秒和当前时间对比)
    const isExpired = Date.now() >= decodedToken.exp * 1000;

    if (isExpired) {
      // 调用刷新token的接口,假设refreshToken存在Redux中
      const refreshResponse = await axiosInstance.post('/refresh-token', {
        refreshToken: store.getState().auth.refreshToken
      });
      const newAccessToken = refreshResponse.data.accessToken;
      
      // 更新Redux中的token
      store.dispatch(setAccessToken(newAccessToken));
      // 给请求头带上新token
      req.headers.Authorization = `Bearer ${newAccessToken}`;
    } else {
      req.headers.Authorization = `Bearer ${accessToken}`;
    }
  }

  return req;
});

注意:这种方式只适用于纯客户端渲染的React应用,SSR场景下可能会有状态共享问题。


方案2:同步Token到本地存储

在Redux更新token的同时,把token存入LocalStorage或SessionStorage,拦截器直接从本地存储读取。

步骤:

  1. 在Auth Slice中同步token到本地存储:
// authSlice.js
import { createSlice } from '@reduxjs/toolkit';

const authSlice = createSlice({
  name: 'auth',
  initialState: {
    // 初始化时从本地存储读取token
    accessToken: localStorage.getItem('accessToken') || null,
    refreshToken: localStorage.getItem('refreshToken') || null
  },
  reducers: {
    setAuthTokens: (state, action) => {
      state.accessToken = action.payload.accessToken;
      state.refreshToken = action.payload.refreshToken;
      // 同步到本地存储
      localStorage.setItem('accessToken', action.payload.accessToken);
      localStorage.setItem('refreshToken', action.payload.refreshToken);
    },
    clearAuthTokens: (state) => {
      state.accessToken = null;
      state.refreshToken = null;
      localStorage.removeItem('accessToken');
      localStorage.removeItem('refreshToken');
    }
  }
});

export const { setAuthTokens, clearAuthTokens } = authSlice.actions;
export default authSlice.reducer;
  1. 在Axios拦截器中读取本地存储的token:
import axios from "axios";
import jwtDecode from "jwt-decode";
import { store } from './store';
import { setAuthTokens } from './authSlice';

const axiosInstance = axios.create({
  baseURL: "http://localhost:5000/api/v1",
});

axiosInstance.interceptors.request.use(async (req) => {
  const accessToken = localStorage.getItem('accessToken');

  if (accessToken) {
    const decodedToken = jwtDecode(accessToken);
    const isExpired = Date.now() >= decodedToken.exp * 1000;

    if (isExpired) {
      const refreshResponse = await axiosInstance.post('/refresh-token', {
        refreshToken: localStorage.getItem('refreshToken')
      });
      const { accessToken: newAccessToken, refreshToken: newRefreshToken } = refreshResponse.data;
      
      // 更新Redux和本地存储
      store.dispatch(setAuthTokens({ accessToken: newAccessToken, refreshToken: newRefreshToken }));
      req.headers.Authorization = `Bearer ${newAccessToken}`;
    } else {
      req.headers.Authorization = `Bearer ${accessToken}`;
    }
  }

  return req;
});

注意:本地存储存在XSS攻击风险,确保你的网站有完善的XSS防护措施;敏感场景建议用HttpOnly Cookie存储refresh token。


方案3:用Redux中间件处理请求逻辑

把请求逻辑放到Redux的异步中间件(比如createAsyncThunk)里,直接在中间件中访问store的状态和dispatch,不需要单独维护Axios拦截器。

示例(用createAsyncThunk):

// thunks.js
import { createAsyncThunk } from '@reduxjs/toolkit';
import axios from 'axios';
import jwtDecode from 'jwt-decode';
import { setAuthTokens } from './authSlice';

const api = axios.create({ baseURL: 'http://localhost:5000/api/v1' });

export const fetchUserData = createAsyncThunk(
  'user/fetchData',
  async (_, { getState, dispatch }) => {
    const { accessToken, refreshToken } = getState().auth;
    let currentToken = accessToken;

    if (currentToken) {
      const decoded = jwtDecode(currentToken);
      if (Date.now() >= decoded.exp * 1000) {
        // 刷新token
        const refreshRes = await api.post('/refresh-token', { refreshToken });
        const { accessToken: newAccessToken, refreshToken: newRefreshToken } = refreshRes.data;
        currentToken = newAccessToken;
        dispatch(setAuthTokens({ accessToken: newAccessToken, refreshToken: newRefreshToken }));
      }
    }

    // 发起请求
    const response = await api.get('/user/profile', {
      headers: { Authorization: currentToken ? `Bearer ${currentToken}` : '' }
    });
    return response.data;
  }
);

这种方式适合将请求逻辑和状态管理深度绑定,避免在拦截器中单独处理token逻辑,但需要每个请求都用thunk封装。


内容的提问来源于stack exchange,提问作者DevRohan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 00:20:30