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;
测试:
先用node server.js
启动服务,然后npm run dev
启动前端
解释代码:
4.利用axios-retry 插件实现请求
npm i axios-retry -S
axiosRetry(instance, {
retries: 3, // 设置重试次数
retryDelay: () => 500, // 设置重试延迟时间
shouldResetTimeout: true, // 重置请求超时时间
retryCondition: (error) => ['ECONNABORTED', 'ERR_NETWORK'].includes(error.code!), // 重试条件
})
服务器代码
测试如下,如果错了它会自动发起请求,连发三次