axios拦截器应用-无感刷新token

19 阅读1分钟
// 添加全局状态管理
let isRefreshing = false;
let failedQueue: Array<{
  resolve: (value?: any) => void;
  reject: (reason?: any) => void;
  config: AxiosRequestConfig;
}> = [];

// 处理队列中的请求
const processQueue = (error: any, token: string | null = null) => {
  failedQueue.forEach(({ resolve, reject, config }) => {
    if (error) {
      reject(error);
    } else if (token) {
      config.headers = {
        ...config.headers,
        Authorization: token
      };
      resolve(request(config));
    }
  });
  
  failedQueue = [];
};

// 修改响应拦截器
request.interceptors.response.use(
  (response: CustomAxiosResponse<Result>) => {
    if (response.config?.resInterceptors) {
      return response.config.resInterceptors(response);
    }
    const res = response.data;
    if (res.result === "NO_LOGIN") {
      return Promise.reject(res.resultMsg);
    }
    if (res.result === "Failure") {
      message.error(res.resultMsg || "API调用错误");
      return Promise.reject(res.resultMsg);
    }
    return Promise.resolve(res);
  },
  async (error: any) => {
    const { response } = error;
    const originalRequest = error.config;

    if (response?.status === 401 && !originalRequest._retry) {
      if (isRefreshing) {
        // 如果正在刷新 token,则把请求加入队列
        return new Promise((resolve, reject) => {
          failedQueue.push({
            resolve,
            reject,
            config: originalRequest
          });
        });
      }

      originalRequest._retry = true;
      isRefreshing = true;

      try {
        // 执行 token 刷新逻辑
        const refreshToken = useSystemStore().refreshToken;
        // 假设有一个刷新 token 的 API 方法
        const newToken = await refreshTokenAPI(refreshToken);
        
        // 更新 store 中的 token
        useSystemStore().setAuthorization(newToken);
        
        // 处理队列中的请求
        processQueue(null, newToken);
        
        // 重新发送当前请求
        originalRequest.headers.Authorization = newToken;
        return request(originalRequest);
      } catch (refreshError) {
        // token 刷新失败,清空队列并拒绝所有请求
        processQueue(refreshError, null);
        // 可以在这里执行登出操作
        // logout();
        return Promise.reject(refreshError);
      } finally {
        isRefreshing = false;
      }
    }

    message.error(showMessage(response?.code));
    return Promise.reject(error || { code: "999", msg: "API调用错误" });
  }
);