如何在Axios拦截器中获取Redux存储的Access Token并处理过期?
解决Axios拦截器中获取Redux存储Access Token的方案
下面是几个实用的解决方案,帮你在组件外的Axios拦截器里获取Redux中的Access Token:
方案1:直接导入Redux Store实例
在创建Redux Store的时候,把实例导出,拦截器里直接通过store.getState()读取状态。
步骤:
- 在Store配置文件中导出store实例:
// store.js import { configureStore } from '@reduxjs/toolkit'; import authReducer from './authSlice'; // 导出store实例 export const store = configureStore({ reducer: { auth: authReducer, }, });
- 在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,拦截器直接从本地存储读取。
步骤:
- 在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;
- 在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
相关产品推荐
相关产品推荐

