IT评测·应用市场-qidao123.com
标题:
Axios 请求取消:从原理到实践
[打印本页]
作者:
渣渣兔
时间:
2025-3-19 12:56
标题:
Axios 请求取消:从原理到实践
Axios 请求取消:从原理到实践
在现代前端开辟中,网络请求是不可或缺的一部门。Axios 是一个基于 Promise 的 HTTP 客户端,广泛应用于浏览器和 Node.js 环境中。然而,在某些场景下,我们可能需要取消正在进行的请求,比方用户在请求完成前跳转到其他页面,大概重复触发雷同的请求时取消之前的请求。本文将深入探讨 Axios 请求取消的原理,并通过一个二次封装的例子来演示怎样实现请求取消。
1. 请求取消的原理
Axios 的请求取消功能依赖于 CancelToken。CancelToken 是一个用于取消请求的令牌,它可以通过 CancelToken.source() 方法创建。每个 CancelToken 实例都有一个 token 和一个 cancel 方法。当调用 cancel 方法时,与该 token 关联的请求将被取消。
1.1 CancelToken 的工作原理
创建 CancelToken
: 通过 CancelToken.source() 方法创建一个 CancelToken 实例,该实例包含一个 token 和一个 cancel 方法。
关联请求
: 在发起请求时,将 token 通报给 Axios 请求设置中的 cancelToken 字段。
取消请求
: 当需要取消请求时,调用 cancel 方法,Axios 会中断与该 token 关联的请求。
1.2 取消请求的流程
用户触发某个操作,发起一个请求。
在请求完成之前,用户触发了另一个操作,需要取消之前的请求。
调用 cancel 方法,Axios 中断之前的请求。
发起新的请求。
2. 二次封装 Axios 实现请求取消
为了更好地管理请求取消逻辑,我们可以对 Axios 进行二次封装。以下是一个简单的封装示例,展示了怎样在封装中实现请求取消功能。
1. 代码结构分析
1.1 Axios 实例的创建
const instance: AxiosInstance = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL,
timeout: 10000,
headers: {
'Content-Type': 'application/json',
},
});
复制代码
baseURL
: 从环境变量中获取 API 的基础 URL。
timeout
: 设置请求超时时间为 10 秒。
headers
: 设置默认请求头为 application/json。
通过 axios.create 创建了一个 Axios 实例 instance,后续的全部请求都将基于这个实例。
1.2 取消令牌的管理
const cancelTokenMap = new Map<string, CancelTokenSource>();
复制代码
cancelTokenMap
: 使用 Map 数据结构来存储每个请求的取消令牌。键是请求的 URL,值是对应的 CancelTokenSource。
作用
: 通过 URL 快速查找和取消对应的请求。
1.3 请求拦截器
instance.interceptors.request.use(
(config) => {
// 添加 token 到请求头
const token = localStorage.getItem('token');
if (token) {
config.headers = config.headers || {};
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
(error) => {
return Promise.reject(error);
}
);
复制代码
功能
: 在请求发送前,查抄本地存储中是否存在 token,如果存在则将其添加到请求头中。
作用
: 实现全局的请求头管理,比方身份验证。
1.4 响应拦截器
instance.interceptors.response.use(
(response: AxiosResponse) => {
// 清理已完成的请求记录
const url = response.config.url;
if (url && cancelTokenMap.has(url)) {
cancelTokenMap.delete(url);
}
// 处理全局响应逻辑
if (response.data.code !== 0) {
return Promise.reject(response.data);
}
return response.data;
},
(error) => {
// 清理失败的请求记录
const url = error.config?.url;
if (url && cancelTokenMap.has(url)) {
cancelTokenMap.delete(url);
}
// 处理全局错误
if (error.response?.status === 401) {
// 处理未授权
window.location.href = '/login';
}
return Promise.reject(error);
}
);
复制代码
功能
:
在请求乐成时,清理 cancelTokenMap 中对应的请求记载。
在请求失败时,清理 cancelTokenMap 中对应的请求记载,并根据状态码处置惩罚全局错误(比方未授权时跳转到登录页)。
作用
: 实现全局的响应和错误处置惩罚逻辑。
1.5 封装的请求方法
const http = {
get: <T>(url: string, config?: AxiosRequestConfig): Promise<T> => {
const source = axios.CancelToken.source();
cancelTokenMap.set(url, source);
return instance.get(url, { ...config, cancelToken: source.token });
},
post: <T>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T> => {
const source = axios.CancelToken.source();
cancelTokenMap.set(url, source);
return instance.post(url, data, { ...config, cancelToken: source.token });
},
put: <T>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T> => {
const source = axios.CancelToken.source();
cancelTokenMap.set(url, source);
return instance.put(url, data, { ...config, cancelToken: source.token });
},
delete: <T>(url: string, config?: AxiosRequestConfig): Promise<T> => {
const source = axios.CancelToken.source();
cancelTokenMap.set(url, source);
return instance.delete(url, { ...config, cancelToken: source.token });
},
// 取消指定请求
cancelRequest: (url: string) => {
const source = cancelTokenMap.get(url);
if (source) {
source.cancel(`Request canceled: ${url}`);
cancelTokenMap.delete(url);
}
},
// 取消所有请求
cancelAllRequests: () => {
cancelTokenMap.forEach((source, url) => {
source.cancel(`Request canceled: ${url}`);
cancelTokenMap.delete(url);
});
},
};
复制代码
功能
:
封装了 get、post、put、delete 方法,每个方法都会为请求创建一个 CancelToken,并将其存储到 cancelTokenMap 中。
提供了 cancelRequest 和 cancelAllRequests 方法,用于取消指定请求或全部请求。
作用
: 简化请求调用,并提供机动的请求取消功能。
2. 请求取消的实现原理
2.1 CancelToken 的作用
CancelToken.source()
: 创建一个 CancelTokenSource 对象,包含 token 和 cancel 方法。
token
: 用于关联请求。
cancel
: 用于取消请求。
2.2 请求取消的流程
发起请求时,创建一个 CancelTokenSource,并将其存储到 cancelTokenMap 中。
如果需要取消请求,调用 cancelRequest 或 cancelAllRequests 方法。
调用 cancel 方法后,Axios 会中断与该 token 关联的请求,并抛出一个 Cancel 错误。
在响应拦截器中,清理已完成的请求记载。
3. 使用场景
3.1 取消重复请求
当用户快速点击按钮多次触发雷同的请求时,可以通过 cancelRequest 方法取消之前的请求,只保存最后一次请求。
http.get('/api/data')
.then((data) => console.log(data))
.catch((error) => {
if (axios.isCancel(error)) {
console.log('Request canceled:', error.message);
} else {
console.error('Error:', error);
}
});
// 取消之前的请求
http.cancelRequest('/api/data');
复制代码
3.2 页面跳转时取消请求
当用户跳转到其他页面时,可以通过 cancelAllRequests 方法取消全部未完成的请求,制止无效请求占用资源。
window.addEventListener('beforeunload', () => {
http.cancelAllRequests();
});
复制代码
完备代码
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse, CancelTokenSource } from 'axios';// 创建axios实例const instance: AxiosInstance = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL,
timeout: 10000,
headers: {
'Content-Type': 'application/json',
},
});
// 创建一个Map来存储取消令牌const cancelTokenMap = new Map<string, CancelTokenSource>();
// 请求拦截器instance.interceptors.request.use( (config) => { // 在这里可以添加token等全局请求头 const token = localStorage.getItem('token'); if (token) { config.headers = config.headers || {}; config.headers.Authorization = `Bearer ${token}`; } return config; }, (error) => { return Promise.reject(error); });// 响应拦截器instance.interceptors.response.use( (response: AxiosResponse) => { // 清理已完成的请求记载 const url = response.config.url; if (url && cancelTokenMap.has(url)) { cancelTokenMap.delete(url); } // 在这里处置惩罚全局响应逻辑 if (response.data.code !== 0) { return Promise.reject(response.data); } return response.data; }, (error) => { // 清理失败的请求记载 const url = error.config?.url; if (url && cancelTokenMap.has(url)) { cancelTokenMap.delete(url); } // 在这里处置惩罚全局错误 if (error.response?.status === 401) { // 处置惩罚未授权 window.location.href = '/login'; } return Promise.reject(error); });// 封装请求方法const http = { get: <T>(url: string, config?: AxiosRequestConfig): Promise<T> => { const source = axios.CancelToken.source(); cancelTokenMap.set(url, source); return instance.get(url, { ...config, cancelToken: source.token }); }, post: <T>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T> => { const source = axios.CancelToken.source(); cancelTokenMap.set(url, source); return instance.post(url, data, { ...config, cancelToken: source.token }); }, put: <T>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T> => { const source = axios.CancelToken.source(); cancelTokenMap.set(url, source); return instance.put(url, data, { ...config, cancelToken: source.token }); }, delete: <T>(url: string, config?: AxiosRequestConfig): Promise<T> => { const source = axios.CancelToken.source(); cancelTokenMap.set(url, source); return instance.delete(url, { ...config, cancelToken: source.token }); }, // 添加取消请求的方法 // http.cancelRequest('/api/some-endpoint'); cancelRequest: (url: string) => { const source = cancelTokenMap.get(url); if (source) { source.cancel(`Request canceled: ${url}`); cancelTokenMap.delete(url); } }, // 取消全部请求 cancelAllRequests: () => { cancelTokenMap.forEach((source, url) => { source.cancel(`Request canceled: ${url}`); cancelTokenMap.delete(url); }); },};export default http;
复制代码
4. 总结
通过二次封装 Axios,我们实现了一个功能强盛且易于使用的 HTTP 客户端。它不光支持全局的请求和响应拦截,还提供了机动的请求取消功能,适用于多种场景。盼望本文能帮助你更好地理解和使用 Axios 的请求取消功能。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
欢迎光临 IT评测·应用市场-qidao123.com (https://dis.qidao123.com/)
Powered by Discuz! X3.4