如何实现接口错误重试

464 阅读2分钟

前言

在我们实际写业务过程中,可能会遇到一种需求,比如某个接口因为网络啥的原因不稳定 会报错,这时候我们就需要一种错误重试机制,比如失败我们就重试 4 次,4 次还不行就算真的失败了,那这个功能具体需要怎么实现呢?

实现

接口本身是个返回 promise的函数,我们需要做的就是拦截 promise 的报错,在报错中加入重试机制,具体做法就是在promise的catch中返回一个新的promise,并将resolve和reject方法传递给onError回调,以此实现控制权转移;

function getRetryRequest() {
  let retries = 0; // 重试次数
​
  function load(
    api: () => Promise<any>,
    onError?: (retry: Function, fail: Function, retries: number, err: any) => void,
  ) {
    // 拦截报错 将报错控制权交给onError回调
    return api().catch((err) => {
      if (!onError) throw err;
      return new Promise((resolve, reject) => {
        // 重试函数
        const retry = () => {
          resolve(load(api, onError));
          retries++;
        };
        // 失败函数
        const fail = () => {
          reject(err);
        };
        // 执行错误回调
        onError(retry, fail, retries, err);
      });
    });
  }
​
  return load;
}

在 load 方法中,如果接口本身响应正常就直接返回了,只有报错时候才能进入 catch 环节,这时候就需要记录重试次数,并将是否重试或者失败的控制权通过 onError 回调转移给使用者。

以下是一个实际的使用例子

// 模拟请求接口网络不好 请求的第5次才能成功
let count = 0;
const api = () => {
  return new Promise((resolve, reject) => {
    if (count < 5) {
      reject("网络异常");
    } else {
      console.log("请求成功");
      resolve("请求成功");
    }
    count++;
  });
};
​
// 调用接口 增加重试逻辑
const request = getRetryRequest();
request(api, (retry, fail, retries, err) => {
  if (retries < 5) {
    if (retries == 0) {
      console.info(`首次请求, err: ${err}`);
    } else {
      console.info(`第${retries}次重试, err: ${err}`);
    }
    retry();
  } else {
    console.info(`超过重试次数 按照失败处理`);
    fail();
  }
});

这里有一个需要注意地方,模拟请求接口是请求 5 次才能成功,意味着除了第 1 次请求,一共要重试 4 次才能成功。

因为控制权在调用者手里,所以这里你也可以改成延时 1s 后再重试都可以。

重试次数