有个需求,网络请求超时的情况下进行网络请求的重试,并可以指定重新请求的次数。

这篇文档总结的不错https://github.com/ssttm169/use-axios-well

思路也很清晰,大致是

  1. axios config中添加自定义的熟属性,如重新请求的最大次数、请求的间隔时间
  2. interceptors.response中对网络请求失败的场景进行判断,进行重新请求或其他操作。

需要额外注意,0.19.0有个bug,不支持config中自定义属性,不过旧版本如0.18.1是支持的。详情追踪issue,之后的版本肯定会修复。

示例如下:

export default function $axios(options) {
  return new Promise((resolve, reject) => {
    const instance = axios.create({
      baseURL: process.env.VUE_APP_BASE_API,
      timeout: 1000 * 15,
      withCredentials: false
    });

    instance.interceptors.request.use(
      config => {
        if (store.getters.token) {
          config.headers["th-token"] = store.getters.token;
        }
        return config;
      },
      error => {
        return Promise.reject(error);
      }
    );

    //https://github.com/ssttm169/use-axios-well
    //@0.19.0有个bug https://github.com/axios/axios/issues/2203
    //先使用 0.18.1
    instance.interceptors.response.use(
      res => {
        if (res.data.succ) {
          //如果后台返回的json显示成功,pass
          return res;
        } else {
          if (res.data.code === Code.UNAUTHEN || res.data.code === Code.SESSION_TIMOUT) {
            //处理登录相关的错误
            MessageBox.confirm("你已被登出,可以取消继续留在该页面,或者重新登录", "确定登出", {
              confirmButtonText: "重新登录",
              cancelButtonText: "取消",
              type: "warning"
            }).then(() => {
              store.dispatch("LogOut").then(() => {
                location.reload();
              });
            });
          } else {
            //其它错误弹出错误信息
            Message({ message: res.data.msg, type: "error", duration: 5000 });
          }
          return Promise.reject(res);
        }
      },
      err => {
        //判断请求超时的判断
        if (err.code === "ECONNABORTED" && err.message.indexOf("timeout") !== -1) {
          let config = err.config;
          if (!config || !config.retry) {
            return Promise.reject(err);
          }
          config.__retryCount = config.__retryCount || 0;
          if (config.__retryCount >= config.retry) {
            Message({ message: "请求超时", type: "error", duration: 5000 });
            return Promise.reject(err);
          }
          // Increase the retry count
          config.__retryCount += 1;
          let backoff = new Promise(function(resolve) {
            setTimeout(function() {
              resolve();
            }, config.retryDelay || 1);
          });
          // Return the promise in which recalls axios to retry the request
          return backoff.then(function() {
            return instance(config);
          });
        }
        Message({ message: err.message, type: "error", duration: 5000 });
        return Promise.reject(err);
      }
    );
    //请求处理
    instance(options)
      .then(res => {
        resolve(res);
      })
      .catch(error => {
        reject(error);
      });
  });
}

基本调用:

export default function $get(url, timeout, retry, retryDelay) {
  let config = {
    url: replace.replaceUrl(url),
    timeout: (timeout || 30) * 1000,
    retry: retry || 0,
    retryDelay: retryDelay
  };
  return new Promise((resolve, reject) => {
    request(config)
      .then(response => {
        resolve(response.data);
      })
      .catch(error => {
        reject(error);
      });
  });
}

代码见gist https://gist.github.com/tyrad/470d7a3bc4cbdf434c286f9739eaf268