我想在AXIOS "axios": "^1.3.4",中在后台刷新令牌,当服务器端返回访问令牌到期时,客户端将请求存储在队列中,并在新令牌刷新后恢复请求.当我使用Promise时,我的react 是这样的:

instance.interceptors.response.use((response:AxiosResponse<any, any>) => {
  const originalRequest:InternalAxiosRequestConfig<any> = response.config;
  if(isRefreshing){
    addRequestToQueue(originalRequest);
  }
  if (!isRefreshing) {
    if(response.data.resultCode === ResponseCode.ACCESS_TOKEN_EXPIRED){
      addRequestToQueue(originalRequest);
      isRefreshing = true;
      // refresh the access token
      ResponseHandler.handleWebCommonFailure(response.data)
      .then((data:any) => {
        isRefreshing = false;
        pendingRequestsQueue.forEach((request) => {
          const accessToken = localStorage.getItem(WheelGlobal.ACCESS_TOKEN_NAME);
          request.resolve(accessToken)
          .then((resp:any)=>{
            // get the action of original request
            const action = request.action;
            const data = resp.data.result;
            // change the state to make it render the UI
            store.dispatch(action(data));
          });
        });
        pendingRequestsQueue = [];
      });
    }
  }
  return response;
},
  (error: any) => { return Promise.reject(error) }
)

request.resolve(accessToken)行显示错误caught (in promise) TypeError: Cannot read properties of undefined (reading 'then'),这是定义的addRequestToQueue 函数:

function addRequestToQueue(originalRequest: any){
  return new Promise((resolve, reject) => {
    pendingRequestsQueue.push({ resolve, reject });
  })
    .then((data:any) => {
      originalRequest.headers['x-access-token'] = data.accessToken;
      originalRequest.headers['x-request-id'] = uuid();
      return instance(originalRequest);
    })
    .catch((err) => {
      return Promise.reject(err);
    });
}

我应该做些什么来解决这个问题?这是我的AXIOS客户端的完整代码:

import axios, { AxiosResponse, InternalAxiosRequestConfig } from 'axios';
import { v4 as uuid } from 'uuid';
import store from '../store/store';
import { ResponseCode, ResponseHandler, WheelGlobal } from 'js-wheel';

let isRefreshing = false
let pendingRequestsQueue: Array<any> = [];

const instance = axios.create({
  timeout: 60000
})

instance.defaults.headers.post['Content-Type'] = 'application/json'

instance.interceptors.request.use((request) => {
  const accessToken = localStorage.getItem(WheelGlobal.ACCESS_TOKEN_NAME);
  accessToken && (request.headers['x-access-token'] = accessToken);
  request.headers['x-request-id'] = uuid();
  return request
},
  (error: any) => {
    return Promise.reject(error)
  }
)

function addRequestToQueue(originalRequest: any): Promise<any> {
  return new Promise((resolve, reject) => {
    pendingRequestsQueue.push({ resolve, reject });
  })
    .then((data: any) => {
      originalRequest.headers['x-access-token'] = data.accessToken;
      originalRequest.headers['x-request-id'] = uuid();
      return instance(originalRequest);
    })
    .catch((err) => {
      return Promise.reject(err);
    });
}

instance.interceptors.response.use((response: AxiosResponse<any, any>) => {
  const originalRequest: InternalAxiosRequestConfig<any> = response.config;
  if (isRefreshing) {
    addRequestToQueue(originalRequest);
  }
  if (!isRefreshing) {
    if (response.data.resultCode === ResponseCode.ACCESS_TOKEN_EXPIRED) {
      addRequestToQueue(originalRequest);
      isRefreshing = true;
      // refresh the access token
      ResponseHandler.handleWebCommonFailure(response.data)
        .then((data: any) => {
          isRefreshing = false;
          pendingRequestsQueue.forEach((request) => {
            const accessToken = localStorage.getItem(WheelGlobal.ACCESS_TOKEN_NAME);
            const promise = request.resolve(accessToken);
            if (promise) {
              promise.then((resp: any) => {
                // get the action of original request
                const action = request.action;
                const data = resp.data.result;
                // change the state to make it render the UI
                store.dispatch(action(data));
              });
            }
          });
          pendingRequestsQueue = [];
        });
    }
  }
  return response;
},
  (error: any) => { return Promise.reject(error) }
)

export function requestWithAction(config: any, action: (arg0: any) => any) {
  return instance(config).then(
    (response: { data: { result: any; }; }) => {
      const data = response.data.result;
      store.dispatch(action(data));
      return response.data;
    }
  ).catch(
    (error: any) => {
      console.error(error);
    }
  );
}

推荐答案

问题是,resolve不会回报promise .它返回undefined.

退一步说,您不应该需要像addRequestToQueue这样的函数来创建新的Promise并将其resolve函数推入队列.在已经promise 使用(instance())的情况下创建new Promise是一种反模式.

相反,将请求放入队列并调用主函数中的axios(instance),您可以在其上链接then调用.就像这样:

instance.interceptors.response.use((response:AxiosResponse<any, any>) => {
  const originalRequest:InternalAxiosRequestConfig<any> = response.config;
  if(isRefreshing){
    pendingRequestsQueue.push(originalRequest); // <--
  }
  if (!isRefreshing) {
    if(response.data.resultCode === ResponseCode.ACCESS_TOKEN_EXPIRED){
      pendingRequestsQueue.push(originalRequest); // <--
      isRefreshing = true;
      // refresh the access token
      ResponseHandler.handleWebCommonFailure(response.data)
      .then((data:any) => {
        isRefreshing = false;
        pendingRequestsQueue.forEach((request) => {
          const accessToken = localStorage.getItem(WheelGlobal.ACCESS_TOKEN_NAME);
          // Moved code from `addRequestsToQueue` here:
          request.headers['x-access-token'] = accessToken;
          request.headers['x-request-id'] = uuid();
          instance(request) // This returns a promise (contrary to `resolve`)
          .then((resp:any)=>{
            // get the action of original request
            const action = request.action;
            const data = resp.data.result;
            // change the state to make it render the UI
            store.dispatch(action(data));
          });
        });
        pendingRequestsQueue = [];
      });
    }
  }
  return response;
},
  (error: any) => { return Promise.reject(error) }
)

Typescript相关问答推荐

Tailwind CSS样式不在Svelte应用程序中呈现

TypScript手册中的never[]参数类型是什么意思?

单击并移除for循环中的一项也会影响另一项

Angular 信号:当输入信号改变值时,S触发取数的正确方式是什么?

具有泛型类方法的类方法修饰符

我可以为情态车使用棱角形的路由守卫吗?

TypeError:正文不可用-NextJS服务器操作POST

TypeScrip泛型类未提供预期的类型错误

作为函数参数的联合类型的键

如何定义这样一个TypeScript泛型,遍历路由配置树并累积路径

在单独的组件中定义React Router路由

打字脚本错误:`不扩展[Type]`,而不是直接使用`[Type]`

如何键入对象转换器

如何从抽象类的静态方法创建子类的实例?

有没有一种方法可以提升对象的泛型级别,而对象的值是泛型函数?

可以将JS文件放在tsconfig';s includes/files属性?或者,我如何让tsc判断TS项目中的JS文件?

我如何键入它,以便具有字符串或数字构造函数的数组可以作为字符串或数字键入s或n

T的typeof键的Typescript定义

Typescript 从泛型推断类型

Typescript 确保通用对象不包含属性