如何阻止axios在已有refresh token请求待处理时重复发起刷新请求
解决方案
核心通过刷新请求锁+待重试请求队列实现,避免重复发起刷新token请求,改造后的代码如下:
// 新增两个全局变量,放在createResponseInterceptor作用域外侧 let isRefreshing = false; let refreshSubscribers: ((token: string) => void)[] = []; // 新增:订阅重试请求的方法 const subscribeTokenRefresh = (cb: (token: string) => void) => { refreshSubscribers.push(cb); }; // 新增:刷新成功后批量触发所有待重试请求 const onRefreshed = (token: string) => { refreshSubscribers.forEach(cb => cb(token)); refreshSubscribers = []; }; const createResponseInterceptor = () => { const interceptor = axiosClient.interceptors.response.use( (response) => { return response; }, (error: AxiosError) => { const originalRequest = error.config; if (error.response && error.response.status !== 401) { return Promise.reject(error); } axiosClient.interceptors.response.eject(interceptor); console.info('token expired', error.response?.config); // 核心改造逻辑 if (!isRefreshing) { isRefreshing = true; return axiosClient .patch('/auth', { refreshToken: localStorage.getItem('refresh_token'), }) .then((res) => { if (res.status === 200) { const newAccessToken = res.data.accessToken; localStorage.setItem( 'access_token', newAccessToken ); axiosClient.defaults.headers['Authorization'] = newAccessToken; originalRequest.headers['Authorization'] = newAccessToken; // 触发所有等待中的请求重试 onRefreshed(newAccessToken); return axiosClient(originalRequest); } }) .catch((err) => { if (err.response && err.response.status === 401) { localStorage.removeItem('access_token'); localStorage.removeItem('refresh_token'); window.location.href = '/login'; return Promise.reject(err); } else { console.info('error failed'); axiosClient.interceptors.response.eject(interceptor); return Promise.reject(err); } }) .finally(() => { // 释放刷新锁 isRefreshing = false; createResponseInterceptor(); }); } else { // 已经有刷新请求在处理,将当前请求加入等待队列 return new Promise((resolve) => { subscribeTokenRefresh((token: string) => { originalRequest.headers['Authorization'] = token; resolve(axiosClient(originalRequest)); }) }) } } ); };
关键逻辑说明
isRefreshing是全局状态锁,保证同一时间最多只有一个刷新token的请求被发起refreshSubscribers队列会暂存所有刷新token期间返回401的请求,等token刷新成功后,统一用新的token批量重试所有暂存的请求- 后续触发401的请求不会重复调用刷新接口,只会等待锁释放后拿到新token重试原有请求
内容的提问来源于stack exchange,提问作者arnodorian067
相关产品推荐
相关产品推荐

