React项目中Axios调用刷新令牌接口返回401错误的解决咨询
排查并解决Axios调用刷新令牌接口返回401的问题
问题背景
在Windows 10环境下使用react-router-dom 5.2.0、react-redux 7.2.5、React 17.0.2、axios 0.21.4开发图片上传功能时,调用/api/v1/users/token/refresh/接口返回401错误,该问题在封装axiosInstance箭头函数后出现,怀疑问题出在axiosInstance.js文件中。
相关代码
axiosInstance.js
import jwt_decode from 'jwt-decode'; import dayjs from 'dayjs'; import axios from 'axios'; import {updateAccessToken} from '../actions/userActions'; const baseURL = 'http://127.0.0.1:8000'; const axiosInstance = (userInfo , dispatch) => { const instance = axios.create({ 'mode': 'cors', baseURL, headers: { 'Content-Type': 'application/json', Authorization:`Bearer ${userInfo?.access}`, } }); instance.interceptors.request.use(async req=> { try { const user = jwt_decode(userInfo.access); const isExpired = dayjs.unix(user.exp).diff(dayjs()) < 5000; if (!(isExpired)) { return req } const response = await axios.post( '/api/v1/users/token/refresh/' , {refresh:userInfo.refresh}, ); dispatch(updateAccessToken(response.data)) req.headers.Authorization = `Bearer ${response.data.access}`; return req; } catch (error) { console.log(error) } }); return instance } export default axiosInstance;
userActions.js
export const userFurtherInformationAction = (image, gender) => async (dispatch, getState) => { try { dispatch({ //USER FURTHER INFORMATION REQUEST type: USER_FURTHER_INFORMATION_REQUEST, }); const {userLogin: {userInfo}} = getState(); const formData = new FormData(); const image_url = URL.createObjectURL(image) formData.append('userPicture', image); formData.append('sex', gender); const authRequestAxios = axiosInstance(userInfo,dispatch); const {data} = await authRequestAxios.post('/api/v1/users/complete_user_further_info/', formData); dispatch({ //USER FURTHER INFORMATION SUCCESS type: USER_FURTHER_INFORMATION_SUCCESS, payload: data, }); localStorage.setItem('userInfo', JSON.stringify(data)); } catch (error) { dispatch({ // USER FURTHER INFORMATION FAILED type: USER_FURTHER_INFORMATION_FAILED, payload: error.response && error.response.data.detail ? error.response.data.detail : error.message, }); } }
问题排查
- 刷新接口地址错误:拦截器中调用刷新令牌接口时,直接使用
axios.post('/api/v1/users/token/refresh/'),未拼接预设的baseURL,导致请求发送到前端项目域名而非后端API域名,后端无法识别请求返回401。 - 拦截器异常处理缺失:catch块捕获错误后未抛出异常,会导致请求带着过期token继续发送,引发401。
- Content-Type冲突:axiosInstance默认设置
Content-Type: application/json,但上传接口使用FormData,该配置会导致后端无法解析请求,间接引发认证类错误。 - refresh令牌有效性存疑:
userInfo.refresh可能存在过期、格式错误或未正确存储的情况。
修复方案
1. 修正刷新接口请求地址
使用已创建的axios实例发送刷新请求,自动携带baseURL:
// 替换原axios.post为instance.post const response = await instance.post( '/api/v1/users/token/refresh/' , {refresh: userInfo.refresh} );
2. 完善拦截器异常处理
在catch块中抛出错误,确保上层能捕获并处理:
catch (error) { console.log(error); return Promise.reject(error); }
3. 适配FormData请求的Content-Type
移除axiosInstance中固定的Content-Type配置,axios会自动识别FormData并设置正确的multipart/form-data:
const instance = axios.create({ 'mode': 'cors', baseURL, headers: { Authorization:`Bearer ${userInfo?.access}`, } });
4. 验证refresh令牌有效性
在调用刷新接口前打印userInfo.refresh的值,确认其未过期、格式符合后端要求,且正确从Redux或localStorage中获取。
修复后的完整axiosInstance.js
import jwt_decode from 'jwt-decode'; import dayjs from 'dayjs'; import axios from 'axios'; import {updateAccessToken} from '../actions/userActions'; const baseURL = 'http://127.0.0.1:8000'; const axiosInstance = (userInfo , dispatch) => { const instance = axios.create({ 'mode': 'cors', baseURL, headers: { Authorization:`Bearer ${userInfo?.access}`, } }); instance.interceptors.request.use(async req=> { try { const user = jwt_decode(userInfo.access); const isExpired = dayjs.unix(user.exp).diff(dayjs()) < 5000; if (!isExpired) { return req; } const response = await instance.post( '/api/v1/users/token/refresh/' , {refresh: userInfo.refresh} ); dispatch(updateAccessToken(response.data)); req.headers.Authorization = `Bearer ${response.data.access}`; return req; } catch (error) { console.log(error); return Promise.reject(error); } }); return instance; } export default axiosInstance;
内容的提问来源于stack exchange,提问作者saman barjawand
相关产品推荐
相关产品推荐

