如何解决Axios拦截器中的无限循环问题
解决Axios拦截器401无限循环问题
原因分析
- 刷新请求触发重复拦截:当修改refresh token导致刷新接口返回401时,该请求会被自定义的response拦截器捕获。由于刷新请求的
config未设置_retry标记,拦截器会再次调用refreshAccessToken,陷入无限循环。 - 失败后未终止错误流程:
refreshAccessToken函数在刷新失败时仅返回Promise.reject(error),未执行登出、清空存储和跳转登录页的逻辑,导致错误状态持续,无法终止循环。
解决方法
方法1:在刷新失败时强制终止流程
修改refreshAccessToken函数,在catch块中添加登出和跳转逻辑,确保刷新失败后直接终止所有请求并跳转登录页:
const refreshAccessToken = async () => { const refresh_token = localStorage.getItem(REFRESH_TOKEN_KEY); if (!refresh_token) { store.dispatch(logout()); localStorage.clear(); window.location.href = "/"; return Promise.reject(new Error("无刷新令牌")); } else { try { const response = await axiosInstance.get(REFRESH_TOKEN_ENDPOINT); const access_token = response.data.access_token; const new_refresh_token = response.data.refresh_token; localStorage.setItem(ACCESS_TOKEN_KEY, access_token); localStorage.setItem(REFRESH_TOKEN_KEY, new_refresh_token); return access_token; } catch (error) { // 刷新失败直接执行登出逻辑 store.dispatch(logout()); localStorage.clear(); window.location.href = "/"; return Promise.reject(error); } } };
方法2:排除刷新请求的拦截逻辑
在response拦截器中,判断当前请求是否是刷新token的接口,如果是且返回401,直接执行登出逻辑,不再进入重试流程:
axiosInstance.interceptors.response.use( (response) => { return response; }, async (error) => { const originalRequest = error.config; // 拦截刷新token请求的401,直接登出 if (originalRequest.url === REFRESH_TOKEN_ENDPOINT && error.response?.status === 401) { store.dispatch(logout()); localStorage.clear(); window.location.href = "/"; return Promise.reject(error); } // 处理其他请求的401重试 if (error.response?.status === 401 && !originalRequest._retry) { originalRequest._retry = true; try { await refreshAccessToken(); return axiosInstance(originalRequest); } catch (error) { return Promise.reject(error); } } return Promise.reject(error); } );
方法3:使用原生axios请求刷新接口(推荐)
避免刷新请求触发自定义拦截器,直接用原生axios而非axiosInstance调用刷新接口:
const refreshAccessToken = async () => { const refresh_token = localStorage.getItem(REFRESH_TOKEN_KEY); if (!refresh_token) { store.dispatch(logout()); localStorage.clear(); window.location.href = "/"; return Promise.reject(new Error("无刷新令牌")); } else { try { // 使用原生axios发起刷新请求,绕过自定义拦截器 const response = await axios.get(`${userEnv.apiUrl}${REFRESH_TOKEN_ENDPOINT}`, { headers: { Authorization: `Bearer ${refresh_token}` } }); const access_token = response.data.access_token; const new_refresh_token = response.data.refresh_token; localStorage.setItem(ACCESS_TOKEN_KEY, access_token); localStorage.setItem(REFRESH_TOKEN_KEY, new_refresh_token); return access_token; } catch (error) { store.dispatch(logout()); localStorage.clear(); window.location.href = "/"; return Promise.reject(error); } } };
内容的提问来源于stack exchange,提问作者raio
相关产品推荐
相关产品推荐

