1、安装axios
yarn add axios
2、新建utils/request.ts
import axios from 'axios';
import { message } from 'antd';
// 创建全局 AbortController 缓存(按请求URL+参数缓存)
const abortControllerMap = new Map();
// 生成唯一请求标识(用于缓存控制器)
const generateRequestId = (config) => {
return `${config.url}`;
};
const service = axios.create({
baseURL: import.meta.env.VITE_API_URL,
timeout: 500000,
});
service.interceptors.request.use(
(config) => {
// 生成请求标识
const requestId = generateRequestId(config);
// 如果已有相同请求则中断前一个
// TODO: 需要改成单独接口配置
if (abortControllerMap.has(requestId) && config.abortable) {
abortControllerMap.get(requestId).abort();
}
// 创建新控制器并缓存
const controller = new AbortController();
config.signal = controller.signal;
abortControllerMap.set(requestId, controller);
const { token } = JSON.parse(localStorage.getItem('x-userInfo') || '{}');
if (token) {
config.headers['Authorization'] = `Bearer ${token}`;
}
return config;
},
(error) => {
return Promise.reject(error);
}
);
service.interceptors.response.use(
(response) => {
const res = response.data;
const requestId = generateRequestId(response.config);
// 请求完成后清理缓存控制器
if (abortControllerMap.has(requestId)) {
abortControllerMap.delete(requestId);
}
// 二进制数据则直接返回
if (
response.request.responseType === "blob" ||
response.request.responseType === "arraybuffer"
) {
return res;
}
if (res.error_code === 400004) {
message.error(res.message || '您还未登录,请先去登录');
return Promise.reject(res);
} else if (res.error_code !== 0) {
message.error(res.message || 'Error');
return Promise.reject(new Error(res.message || 'Error'));
} else {
return res;
}
},
(error) => {
// 如果是取消请求导致的错误(code:ERR_CANCELED)
if (axios.isCancel(error)) {
console.log('请求被取消:', error.message);
return Promise.reject({
type: 'abort',
message: 'Request canceled'
});
}
console.log('请求错误 ', error);
message.error(error.message);
return Promise.reject(error);
}
);
// 封装带中断能力的get请求
export function get(url, params, config = {}) {
return service({
url,
method: 'get',
params,
...config,
});
}
// 封装带中断能力的post请求
export function post(url: string, data: any, config = {}) {
return service({
url,
method: 'post',
data,
...config,
});
}
// 新增:全局取消指定请求的方法
export function cancelRequest(config) {
const requestId = generateRequestId(config);
if (abortControllerMap.has(requestId)) {
abortControllerMap.get(requestId).abort();
return true;
}
return false;
}
// 新增:取消所有未完成请求
export function cancelAllRequests() {
abortControllerMap.forEach(controller => controller.abort());
abortControllerMap.clear();
}
export default service;
3、使用
import request from "@/utils/request"
export const loginApi = (data) => {
return request({
url: '/app/login',
method: 'post',
data,
abortable: true
})
}