Axios取消请求,封装全局取消请求,axios-retry请求重试

2,995 阅读3分钟

axios取消请求有2种方式:一个是利用浏览器内置的AbortController对象,另一个是利用Axios自带的cancelToken对象来实现。

先node写个后端试试看:

import express from 'express';

const app = express();

app.get('/getLongData', async (req, res) => {
  res.setHeader('Access-Control-Allow-Origin', '*');

  await new Promise((resolve) => {
    setTimeout(() => {
      resolve();
    }, 5000);
  });

  res.send({
    code: 200,
    message: "请求成功!",
  });
});
//监听端口号,启动 Web 服务
app.listen(3000, () => {
  console.log('服务器启动成功,请在http://localhost:3000中访问....');
})


1. AbortController

AbortController 是一个浏览器提供的 API,用于取消正在进行的异步操作,如 Fetch 请求或 Axios 请求。你可以创建一个 AbortController 实例,并在 Axios 请求配置中通过 signal 属性传递它。

import axios from 'axios';

const controller = new AbortController();

axios.get('/foo/bar', {
  signal: controller.signal
}).then(response => {
  // 处理响应
}).catch(error => {
  if (error.name === 'AbortError') {
    console.log('请求被取消');
  } else {
    console.error('发生了一个错误:', error);
  }
});

// 取消请求
controller.abort();

2.cancelToken

CancelToken 是 Axios 自带的一个类,用于实现请求取消功能。你需要创建一个 CancelToken 实例,并在请求配置中通过 cancelToken 属性传递它。

import axios from 'axios';
import CancelToken from 'axios/cancelToken';

let cancel;

// 发起请求
axios.get('/foo/bar', {
  cancelToken: new CancelToken(c => cancel = c)
}).then(response => {
  // 处理响应
}).catch(error => {
  if (axios.isCancel(error)) {
    console.log('请求被取消');
  } else {
    console.error('发生了一个错误:', error);
  }
});

// 取消请求
if (cancel) {
  cancel('取消请求的原因');
}

3.全局封装

新建一个 globalCancelToken.js

// 最新的一个请求
let cancel: any = null;

// 所有请求
let cancelTokenList: any[] = [];

function setToken(cancelToken: any) {
  cancel = cancelToken;
  cancelTokenList.push(cancelToken);
}

function cancelToken() {
  cancel && cancel();
  cancelTokenList.pop();
}

function clearAllToken() {
  while (cancelTokenList.length > 0) {
    let cancel = cancelTokenList.pop();
    console.log(cancel, 'cancel');
    cancel && cancel();
  }
}

export {
  setToken,
  cancelToken,
  clearAllToken,
};


文件中定义了一个数组cancelTokenList 用来存放每一次请求所对应的 cancelToken

在请求拦截器中添加取消请求的配置,相应拦截器中判断错误类型是否为取消请求

import { setToken } from './globalCancelToken.js';
import axios from 'axios';
import { message } from 'antd';

const instance = axios.create({
  baseURL: ' http://127.0.0.1:3000/',
  timeout: 10000,
  timeoutErrorMessage: '请求超时,请稍后重试',
  headers: {
    'Content-Type': 'application/json;charset=UTF-8'
  }
});

// request拦截器
instance.interceptors.request.use(config => {
  config.cancelToken = new axios.CancelToken(c => setToken(c));

  return config;
}, error => {
  console.log(error);
  Promise.reject(error);
});


// 响应拦截器
instance.interceptors.response.use(res => {
  // 未设置状态码则默认成功状态
  const code = res.data.code || '0';
  // 二进制数据则直接返回
  if (res.request.responseType === 'blob' || res.request.responseType === 'arraybuffer') {
    return res.data;
  }
  if (code === 401 || code === '10006') {
    return Promise.reject('无效的会话,或者会话已过期,请重新登录。');
  } else if (code === 500) {
    message.error('服务器挂掉了');
    return Promise.reject(new Error(''));
  } else if (code !== '0') {
    message.error('');
    return Promise.reject('error');
  } else {
    return Promise.resolve(res.data);
  }
},
  error => {
    if (error.name === 'CanceledError') {
      console.log('请求已取消');
      return Promise.reject('请求已取消');
    }
    message.error('请求已取消');
    return Promise.reject(error);
  },
);


export default {
  get(url: string, params?: any, options?: any,) {
    return instance.get(url, { params, ...options });
  },
  post(url: string, params?: any, options?: any) {
    return instance.post(url, params, options);
  }
};

组件使用,app.tsx

import { useState } from 'react';
import { cancelToken, clearAllToken } from './axios/globalCancelToken';
import axios from './axios';

function App() {
  function send() {
    axios.get('/getLongData').then(() => {
      console.log(111);
    });
  }

  function cancelSend() {
    cancelToken();
  }

  function cancelAllSend() {
    clearAllToken();
  }


  return (

    <div>
      <button onClick={send}>发起请求</button>
      <button onClick={cancelSend}>取消最近一次请求</button>
      <button onClick={cancelAllSend}>取消所有请求</button>
    </div>
  );
}

export default App;


测试:

image.png

先用node server.js启动服务,然后npm run dev启动前端

image.png

解释代码:

image.png

image.png

4.利用axios-retry 插件实现请求

npm i axios-retry -S

image.png

axiosRetry(instance, {
  retries: 3, // 设置重试次数
  retryDelay: () => 500, // 设置重试延迟时间
  shouldResetTimeout: true, // 重置请求超时时间
  retryCondition: (error) => ['ECONNABORTED', 'ERR_NETWORK'].includes(error.code!), // 重试条件
})

服务器代码

image.png

测试如下,如果错了它会自动发起请求,连发三次

image.png