AXIOS拦截器处理取消重复请求

2,268 阅读1分钟

CancelToken

这是axios暴露出来的一个方法,让请求进入abort状态,官网例子:

const CancelToken = axios.CancelToken;
const source = CancelToken.source();

axios.get('/user/12345', {
  cancelToken: source.token
}).catch(function (thrown) {
  if (axios.isCancel(thrown)) {
    console.log('Request canceled', thrown.message);
  } else {
    // handle error
  }
});

axios.post('/user/12345', {
  name: 'new name'
}, {
  cancelToken: source.token
})

// cancel the request (the message parameter is optional)
source.cancel('Operation canceled by the user.');

还有第二种用法

const CancelToken = axios.CancelToken;
let cancel;

axios.get('/user/12345', {
  cancelToken: new CancelToken(function executor(c) {
    // An executor function receives a cancel function as a parameter
    cancel = c;
  })
});

// cancel the request
cancel();

将其作为一个构造方法,然后传入一个方法,方法会回调一个参数,这个参数就是让那该请求取消的回调。

请求拦截器中处理重复请求

因为请求的url+params加上request的method,肯定是唯一的,所以我们用这个作为请求的唯一id,得出如下

// 记录存储的对象
const pendingRequest = new Map();
// 参数1 配置
function removePending(config) {
  const {
    method,
    params,
    baseURL,
    data,
  } = config;

  const url = [method, params, baseURL, data].join('&');

  if (pendingRequest.has(url)) {
    const cancel = pendingRequest.get(url);

    cancel();
  }
}

function addPending(config) {
  const {
    method,
    params,
    baseURL,
    data,
  } = config;

  let query = [];
  let payload = [];

  if (params) {
    query = Object.entries(params).map((item) => `${item[0]}=${item[1]}`);
  }

  if (data) {
    payload = Object.entries(params).map((item) => `${item[0]}=${item[1]}`);
  }

  const url = [method, baseURL].concat(query).concat(payload).join('&');

  if (!pendingRequest.has(url)) {
    // eslint-disable-next-line no-param-reassign
    config.cancelToken = new CancelToken(((c) => {
      // executor 函数接收一个 cancel 函数作为参数
      pendingRequest.set(url, c);
    }));
  }
}

axios.interceptors.request.use(
  config => {
   addPending(config);

    return config;
  }
);

这样,就能在每一次请求中记录中不同的请求,并且标记起来了

返回拦截器中删除重复请求对象

需要注意,在response中需要删除掉该唯一的key,不然下一次新的请求进来同样会被干掉,不合理。

axios.interceptors.response.use(
  response => {
   removePending(response.config);
  },
  error => {
    removePending(error.config);
    return Promise.reject(error);
  }
);

在成功和失败后都需要删掉该key,因为这个请求的生命周期已经结束了,删除掉保证下一次请求是正常的。