axios封装对比
现axios封装
import axios from 'axios';// 当前环境语言选项
const language = window.localStorage.getItem('language-option')?.replace(/"/g, '');// 向全局添加下载进度
const addDownloadProgress = (progressEvent) => {if (progressEvent.lengthComputable) {window.isFileDownloading = progressEvent.loaded !== progressEvent.total;} else {window.isFileDownloading = false;}
};axios.defaults.timeout = 100000;
axios.defaults.withCredentials = true;const axiosInstance = axios.create({baseURL: '',
});axiosInstance.interceptors.request.use((config) => {config.headers.Feign = 'feign';const csrftoken = localStorage.getItem('csrftoken');if (csrftoken) {config.headers.forgerydefense = csrftoken.replace(/"/g, '');}config.headers['language-option'] = language || 'zh-CN';config.headers['logName'] = localStorage.getItem('userid');if (config.method === 'get' && config.params) {const tmpParams = {};for (const key in config.params) {if (config.params[key] === undefined) continue;if (config.params[key] instanceof Array) {tmpParams[key] = config.params[key];} else {tmpParams[key] = encodeURIComponent(config.params[key]);}}config.params = tmpParams;}return config;},(error) => Promise.reject(error)
);axiosInstance.interceptors.response.use((response) => (response.status === 200 ? response : response),(error) => {const { response } = error;return response ? Promise.reject(response.data) : Promise.reject(error);}
);const request = (config) => {const conf = config;if (conf.responseType === 'blob') {if (!conf['onDownloadProgress']) {conf['onDownloadProgress'] = addDownloadProgress;}}return new Promise((resolve) => {axiosInstance.request(conf).then((res) => {resolve(res.data instanceof Blob ? res : res.data);});});
};export function get(config) {return request({ ...config, method: 'GET' });
}export function post(config) {return request({ ...config, method: 'POST' });
}export default request;
Axios封装分析报告
- 优点分析
基础配置合理
axios.defaults.timeout = 100000; // 100秒超时,适合大文件下载
axios.defaults.withCredentials = true; // 支持跨域携带cookie
请求拦截器功能完善
axiosInstance.interceptors.request.use((config) => {// 添加Feign标识config.headers.Feign = 'feign';// CSRF防护const csrftoken = localStorage.getItem('csrftoken');if (csrftoken) {config.headers.forgerydefense = csrftoken.replace(/"/g, '');}// 国际化支持config.headers['language-option'] = language || 'zh-CN';// 用户标识config.headers['logName'] = localStorage.getItem('userid');// GET参数编码处理if (config.method === 'get' && config.params) {// 处理undefined值和数组}return config;
});
下载进度支持
const addDownloadProgress = (progressEvent) => {if (progressEvent.lengthComputable) {window.isFileDownloading = progressEvent.loaded !== progressEvent.total;}
};
- 存在的问题
严重问题 - 响应拦截器过于简单
axiosInstance.interceptors.response.use((response) => (response.status === 200 ? response : response), // 逻辑冗余(error) => {const { response } = error;return response ? Promise.reject(response.data) : Promise.reject(error);}
);
问题:
没有统一的错误处理
没有统一的成功响应格式处理
没有网络错误、超时等特殊情况的处理
2. 请求函数设计不合理
const request = (config) => {// ...return new Promise((resolve) => { // 只resolve,不rejectaxiosInstance.request(conf).then((res) => {resolve(res.data instanceof Blob ? res : res.data);});});
};
问题:
使用Promise包装axios,但只处理resolve,不处理reject
错误处理不完整
可能导致Promise永远pending
3. 参数编码逻辑有缺陷
if (config.method === 'get' && config.params) {const tmpParams = {};for (const key in config.params) {if (config.params[key] === undefined) continue;if (config.params[key] instanceof Array) {tmpParams[key] = config.params[key];} else {tmpParams[key] = encodeURIComponent(config.params[key]); // 可能导致双重编码}}config.params = tmpParams;
}
问题:
可能导致双重URL编码
数组处理不完整
没有处理null值
3. 改进建议
- 完善响应拦截器
axiosInstance.interceptors.response.use((response) => {// 统一处理成功响应if (response.status === 200) {return response.data;}return Promise.reject(new Error(`HTTP ${response.status}`));},(error) => {// 统一错误处理if (error.response) {// 服务器返回错误状态码const { status, data } = error.response;switch (status) {case 401:// 处理未授权break;case 403:// 处理禁止访问break;case 404:// 处理资源不存在break;case 500:// 处理服务器错误break;}return Promise.reject(data);} else if (error.request) {// 网络错误return Promise.reject(new Error('网络连接失败'));} else {// 其他错误return Promise.reject(error);}}
);
- 重构请求函数
const request = async (config) => {const conf = config;// 处理下载进度if (conf.responseType === 'blob') {if (!conf['onDownloadProgress']) {conf['onDownloadProgress'] = addDownloadProgress;}}try {const response = await axiosInstance.request(conf);return response.data instanceof Blob ? response : response.data;} catch (error) {// 统一错误处理throw error;}
};
- 优化参数处理
const request = async (config) => {const conf = config;// 处理下载进度if (conf.responseType === 'blob') {if (!conf['onDownloadProgress']) {conf['onDownloadProgress'] = addDownloadProgress;}}try {const response = await axiosInstance.request(conf);return response.data instanceof Blob ? response : response.data;} catch (error) {// 统一错误处理throw error;}
};
- 添加请求重试机制
const requestWithRetry = async (config, retries = 3) => {try {return await request(config);} catch (error) {if (retries > 0 && shouldRetry(error)) {await delay(1000);return requestWithRetry(config, retries - 1);}throw error;}
};
- 总体评价
评分:6/10
优点:
基础配置合理
请求拦截器功能较完善
支持下载进度
有CSRF防护和国际化支持
缺点:
响应拦截器过于简单
错误处理不完整
请求函数设计有缺陷
参数处理逻辑有问题
缺少重试机制
缺少请求/响应日志
建议:
完善错误处理机制
重构请求函数
优化参数处理逻辑
添加请求重试功能
增加请求/响应日志
添加请求取消功能
统一响应格式处理
这个axios封装在基础功能上做得不错,但在错误处理和用户体验方面还有很大改进空间。
加强版本
/*** Axios HTTP请求封装* 提供统一的请求处理、错误处理、重试机制、缓存等功能*** @version 2.0.0* @description 增强版HTTP请求封装,支持请求重试、缓存、取消、进度监控等功能*/import axios from 'axios';// ==================== 配置常量 ====================
const CONFIG = {// 请求配置TIMEOUT: 100000, // 默认超时时间(ms)RETRY_TIMES: 3, // 默认重试次数RETRY_DELAY: 1000, // 重试延迟时间(ms)CACHE_EXPIRE: 5 * 60 * 1000, // 缓存过期时间(ms)// 状态码SUCCESS_CODE: 200, // 成功状态码UNAUTHORIZED: 401, // 未授权FORBIDDEN: 403, // 禁止访问NOT_FOUND: 404, // 资源不存在SERVER_ERROR: 500, // 服务器错误// 请求头HEADERS: {'Content-Type': 'application/json',Feign: 'feign',},
};// ==================== 工具函数 ====================/*** 延迟函数* @param {number} ms - 延迟毫秒数* @returns {Promise} 延迟Promise*/
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));/*** 生成缓存键* @param {Object} config - 请求配置* @returns {string} 缓存键*/
const generateCacheKey = (config) => {const { url, method, params, data } = config;return `${method}:${url}:${JSON.stringify(params)}:${JSON.stringify(data)}`;
};/*** 判断是否应该重试请求* @param {Error} error - 错误对象* @returns {boolean} 是否应该重试*/
const shouldRetry = (error) => {// 网络错误或超时错误应该重试if (!error.response) return true;// 服务器错误(5xx)应该重试const status = error.response.status;return status >= 500 && status < 600;
};/*** 处理请求参数* @param {Object} params - 原始参数* @returns {Object} 处理后的参数*/
const processParams = (params) => {if (!params || typeof params !== 'object') return params;const processed = {};for (const [key, value] of Object.entries(params)) {// 跳过undefined和null值if (value === undefined || value === null) continue;if (Array.isArray(value)) {processed[key] = value;} else if (typeof value === 'object') {// 对象类型转为JSON字符串processed[key] = JSON.stringify(value);} else {// 其他类型转为字符串processed[key] = String(value);}}return processed;
};// ==================== 缓存管理 ====================/*** 简单的内存缓存实现*/
class RequestCache {constructor() {this.cache = new Map();}/*** 设置缓存* @param {string} key - 缓存键* @param {any} value - 缓存值* @param {number} expire - 过期时间(ms)*/set(key, value, expire = CONFIG.CACHE_EXPIRE) {this.cache.set(key, {value,expire: Date.now() + expire,});}/*** 获取缓存* @param {string} key - 缓存键* @returns {any} 缓存值或null*/get(key) {const item = this.cache.get(key);if (!item) return null;if (Date.now() > item.expire) {this.cache.delete(key);return null;}return item.value;}/*** 清除缓存* @param {string} key - 缓存键(可选,不传则清除所有)*/clear(key) {if (key) {this.cache.delete(key);} else {this.cache.clear();}}
}const requestCache = new RequestCache();// ==================== 请求取消管理 ====================/*** 请求取消管理器*/
class CancelManager {constructor() {this.pendingRequests = new Map();}/*** 添加请求到待处理列表* @param {string} key - 请求标识* @param {Function} cancel - 取消函数*/add(key, cancel) {this.pendingRequests.set(key, cancel);}/*** 移除请求* @param {string} key - 请求标识*/remove(key) {this.pendingRequests.delete(key);}/*** 取消指定请求* @param {string} key - 请求标识*/cancel(key) {const cancel = this.pendingRequests.get(key);if (cancel) {cancel();this.remove(key);}}/*** 取消所有请求*/cancelAll() {this.pendingRequests.forEach((cancel) => cancel());this.pendingRequests.clear();}
}const cancelManager = new CancelManager();// ==================== 全局状态管理 ====================// 当前环境语言选项
const language = window.localStorage.getItem('language-option')?.replace(/"/g, '');// 下载进度管理
const addDownloadProgress = (progressEvent) => {if (progressEvent.lengthComputable) {window.isFileDownloading = progressEvent.loaded !== progressEvent.total;} else {window.isFileDownloading = false;}
};// ==================== Axios实例配置 ====================// 设置全局默认配置
axios.defaults.timeout = CONFIG.TIMEOUT;
axios.defaults.withCredentials = true;// 创建axios实例
const axiosInstance = axios.create({baseURL: '',headers: CONFIG.HEADERS,
});// ==================== 请求拦截器 ====================axiosInstance.interceptors.request.use((config) => {// 生成请求标识const requestKey = `${config.method}:${config.url}:${Date.now()}`;config.requestKey = requestKey;// 添加请求头config.headers.Feign = 'feign';// CSRF防护const csrftoken = localStorage.getItem('csrftoken');if (csrftoken) {config.headers.forgerydefense = csrftoken.replace(/"/g, '');}// 国际化支持config.headers['language-option'] = language || 'zh-CN';// 用户标识config.headers['logName'] = localStorage.getItem('userid');// 处理GET请求参数if (config.method === 'get' && config.params) {config.params = processParams(config.params);}// 处理POST请求数据if (config.method === 'post' && config.data) {config.data = processParams(config.data);}// 添加取消令牌const cancelToken = new axios.CancelToken((cancel) => {cancelManager.add(requestKey, cancel);});config.cancelToken = cancelToken;// 请求日志console.log(`🚀 发起请求: ${config.method?.toUpperCase()} ${config.url}`, {params: config.params,data: config.data,headers: config.headers,});return config;},(error) => {console.error('❌ 请求拦截器错误:', error);return Promise.reject(error);}
);// ==================== 响应拦截器 ====================axiosInstance.interceptors.response.use((response) => {const { config, status, data } = response;// 移除请求标识cancelManager.remove(config.requestKey);// 响应日志console.log(`✅ 请求成功: ${config.method?.toUpperCase()} ${config.url}`, {status,data,});// 处理成功响应if (status === CONFIG.SUCCESS_CODE) {return response;}return Promise.reject(new Error(`HTTP ${status}`));},(error) => {// 移除请求标识if (error.config?.requestKey) {cancelManager.remove(error.config.requestKey);}// 请求被取消if (axios.isCancel(error)) {console.log('🚫 请求被取消:', error.message);return Promise.reject(error);}// 响应错误处理if (error.response) {const { status, data, config } = error.response;console.error(`❌ 请求失败: ${config?.method?.toUpperCase()} ${config?.url}`,{status,data,error: error.message,});// 根据状态码处理不同错误switch (status) {case CONFIG.UNAUTHORIZED:// 未授权,跳转到登录页console.warn('⚠️ 用户未授权,请重新登录');// 可以在这里添加跳转登录的逻辑break;case CONFIG.FORBIDDEN:console.warn('⚠️ 访问被禁止');break;case CONFIG.NOT_FOUND:console.warn('⚠️ 请求的资源不存在');break;case CONFIG.SERVER_ERROR:console.warn('⚠️ 服务器内部错误');break;default:console.warn(`⚠️ 请求失败,状态码: ${status}`);}return Promise.reject(data || error);}// 网络错误if (error.request) {console.error('🌐 网络连接失败:', error.message);return Promise.reject(new Error('网络连接失败,请检查网络设置'));}// 其他错误console.error('❌ 请求配置错误:', error.message);return Promise.reject(error);}
);// ==================== 核心请求函数 ====================/*** 核心请求函数* @param {Object} config - 请求配置* @param {Object} options - 额外选项* @returns {Promise} 请求Promise*/
const request = async (config, options = {}) => {const {retry = CONFIG.RETRY_TIMES, // 重试次数retryDelay = CONFIG.RETRY_DELAY, // 重试延迟cache = false, // 是否启用缓存cacheExpire = CONFIG.CACHE_EXPIRE, // 缓存过期时间showLoading = false, // 是否显示加载状态responseFormat = 'standard', // 响应格式: 'standard' | 'direct' | 'auto'} = options;// 处理下载进度if (config.responseType === 'blob') {if (!config.onDownloadProgress) {config.onDownloadProgress = addDownloadProgress;}}// 缓存处理if (cache && config.method?.toLowerCase() === 'get') {const cacheKey = generateCacheKey(config);const cachedData = requestCache.get(cacheKey);if (cachedData) {console.log('📦 使用缓存数据:', cacheKey);return cachedData;}}// 显示加载状态let loadingInstance = null;if (showLoading) {// 这里可以集成Element UI的loading组件// loadingInstance = this.$loading({ text: loadingText });}try {const response = await axiosInstance.request(config);let result;// 根据响应格式处理数据if (response.data instanceof Blob) {// 文件下载,直接返回responseresult = response;} else if (responseFormat === 'direct') {// 直接返回数据,不处理标准格式result = response.data;} else if (responseFormat === 'auto') {// 自动判断:如果有code字段且为0,按标准格式处理;否则直接返回数据if (response.data &&typeof response.data === 'object' &&'code' in response.data) {if (response.data.code === 0) {result =response.data.data !== undefined? response.data.data: response.data;} else {throw new Error(response.data.message || '请求失败');}} else {// 直接返回数组或对象result = response.data;}} else {// 标准格式处理result = response.data;}// 缓存结果if (cache && config.method?.toLowerCase() === 'get') {const cacheKey = generateCacheKey(config);requestCache.set(cacheKey, result, cacheExpire);}return result;} catch (error) {// 重试逻辑if (retry > 0 && shouldRetry(error)) {console.log(`🔄 请求失败,${retryDelay}ms后重试,剩余重试次数: ${retry - 1}`);await delay(retryDelay);return request(config, { ...options, retry: retry - 1 });}throw error;} finally {// 隐藏加载状态if (loadingInstance) {// loadingInstance.close();}}
};// ==================== 便捷方法 ====================/*** GET请求* @param {Object} config - 请求配置* @param {Object} options - 额外选项* @returns {Promise} 请求Promise*/
export function get(config, options = {}) {return request({ ...config, method: 'GET' }, options);
}/*** POST请求* @param {Object} config - 请求配置* @param {Object} options - 额外选项* @returns {Promise} 请求Promise*/
export function post(config, options = {}) {return request({ ...config, method: 'POST' }, options);
}/*** PUT请求* @param {Object} config - 请求配置* @param {Object} options - 额外选项* @returns {Promise} 请求Promise*/
export function put(config, options = {}) {return request({ ...config, method: 'PUT' }, options);
}/*** DELETE请求* @param {Object} config - 请求配置* @param {Object} options - 额外选项* @returns {Promise} 请求Promise*/
export function del(config, options = {}) {return request({ ...config, method: 'DELETE' }, options);
}/*** 文件上传* @param {Object} config - 请求配置* @param {Object} options - 额外选项* @returns {Promise} 请求Promise*/
export function upload(config, options = {}) {const uploadConfig = {...config,method: 'POST',headers: {'Content-Type': 'multipart/form-data',...config.headers,},};return request(uploadConfig, options);
}/*** 文件下载* @param {Object} config - 请求配置* @param {Object} options - 额外选项* @returns {Promise} 请求Promise*/
export function download(config, options = {}) {const downloadConfig = {...config,responseType: 'blob',onDownloadProgress: addDownloadProgress,};return request(downloadConfig, options);
}// ==================== 工具方法 ====================/*** 取消指定请求* @param {string} key - 请求标识*/
export function cancelRequest(key) {cancelManager.cancel(key);
}/*** 取消所有请求*/
export function cancelAllRequests() {cancelManager.cancelAll();
}/*** 清除缓存* @param {string} key - 缓存键(可选)*/
export function clearCache(key) {requestCache.clear(key);
}/*** 设置请求超时时间* @param {number} timeout - 超时时间(ms)*/
export function setTimeout(timeout) {axiosInstance.defaults.timeout = timeout;
}/*** 设置请求头* @param {Object} headers - 请求头*/
export function setHeaders(headers) {Object.assign(axiosInstance.defaults.headers, headers);
}// ==================== 导出 ====================export default request;// 导出配置常量
export { CONFIG };
A. 智能重试机制
// 自动重试失败的请求
const data = await getUsers('admin', {retry: 3, // 重试3次retryDelay: 2000, // 每次间隔2秒
});// 重试条件:网络错误、5xx服务器错误
if (retry > 0 && shouldRetry(error)) {await delay(retryDelay);return request(config, { ...options, retry: retry - 1 });
}
B. 智能缓存系统
// 自动缓存GET请求
const clouds = await getClouds({cache: true, // 启用缓存cacheExpire: 10 * 60 * 1000, // 缓存10分钟
});// 缓存键自动生成
const cacheKey = `${method}:${url}:${JSON.stringify(params)}:${JSON.stringify(data)}`;
C. 多格式响应支持
// 标准格式:{code: 0, data: xxx}
const result = await addSalt(params);// 直接格式:直接返回数据
const data = await getUsers('admin', { responseFormat: 'direct' });// 自动格式:智能判断
const permissions = await getOperations(); // 自动处理权限数组
D. 请求取消功能
// 取消单个请求
import { cancelRequest } from '@/utils/http/axios';
cancelRequest('requestKey');// 取消所有请求
import { cancelAllRequests } from '@/utils/http/axios';
cancelAllRequests();// 组件销毁时自动取消
export default {beforeDestroy() {cancelAllRequests();}
}
E. 文件下载优化
// 专门的下载方法
import { download } from '@/utils/http/axios';const blob = await download({url: '/api/download/file.pdf',method: 'post',data: { fileId: '123' }
}, {retry: 1,retryDelay: 2000,showLoading: true
});
- 使用方法详解
A. 基础使用
import { get, post, put, del } from '@/utils/http/axios';// GET请求
const data = await get({url: '/api/users',params: { page: 1, size: 10 }
});// POST请求
const result = await post({url: '/api/users',data: { name: 'John', age: 30 }
});
B. 高级配置
// 带重试和缓存的请求
const data = await get({url: '/api/config',
}, {retry: 3, // 重试3次retryDelay: 1000, // 重试间隔1秒cache: true, // 启用缓存cacheExpire: 5 * 60 * 1000, // 缓存5分钟responseFormat: 'auto', // 自动响应格式showLoading: true // 显示加载状态
});
C. 文件操作
import { upload, download } from '@/utils/http/axios';// 文件上传
const formData = new FormData();
formData.append('file', file);
const result = await upload({url: '/api/upload',data: formData
});// 文件下载
const blob = await download({url: '/api/download',method: 'post',data: { fileId: '123' }
}, {showLoading: true,loadingText: '文件下载中...'
});
D. 错误处理
try {const data = await getUsers('admin');
} catch (error) {if (error.response) {// 服务器错误console.error('服务器错误:', error.response.status);} else if (error.request) {// 网络错误console.error('网络连接失败');} else {// 其他错误console.error('请求配置错误:', error.message);}
}
- API层使用示例
A. 标准业务接口
// service.js
export function addSalt(params, options = {}) {return post({url: `/api/collect-server/v1/cfg/addSalt`,data: params,}, { ...DEFAULT_OPTIONS, ...options }).then(response => handleResponse(response, true));
}// 使用
const result = await addSalt(saltData, {retry: 2,showLoading: true
});
B. 配置类接口
// service.js
export function getClouds(options = {}) {return get({url: `/api/collect-server/v1/cfg/getClouds`,}, { ...DEFAULT_OPTIONS, ...CACHE_OPTIONS, responseFormat: 'auto', ...options });
}// 使用 - 自动缓存,直接返回数组
const clouds = await getClouds();
C. 权限接口
// common-plat.js
export function getOperations(options = {}) {return post({url: `/api/oauth2/v1/perms/user/operations`,data: { operations: permission },}, { ...DEFAULT_OPTIONS, ...CACHE_OPTIONS, responseFormat: 'auto', ...options });
}// 使用 - 自动处理权限数组
const permissions = await getOperations();
- 性能优化效果
A. 缓存优化
// 配置接口自动缓存5分钟
const clouds = await getClouds(); // 第一次请求
const clouds2 = await getClouds(); // 使用缓存,不发送请求
B. 重试优化
// 网络不稳定时自动重试
const data = await getUsers('admin', { retry: 3 });
// 如果第一次失败,会自动重试3次
C. 请求取消
// 避免重复请求和内存泄漏
// 页面切换时自动取消未完成的请求
- 总结
优化后的axios封装提供了:
✅ 完整的错误处理 - 网络错误、服务器错误、业务错误
✅ 智能重试机制 - 自动重试失败的请求
✅ 智能缓存系统 - 自动缓存配置类接口
✅ 多格式响应支持 - 标准格式、直接格式、自动格式
✅ 请求取消功能 - 避免重复请求和内存泄漏
✅ 文件操作优化 - 专门的上传下载方法
✅ 详细日志记录 - 便于调试和监控
✅ 性能优化 - 缓存、重试、取消等机制
✅ 向后兼容 - 现有代码无需修改
✅ 易于扩展 - 模块化设计,便于添加新功能
这个封装大大提升了开发效率和用户体验,是现代Web应用HTTP请求处理的最佳实践!
使用方法
xios封装使用方法大全
- 基础HTTP方法使用
GET请求
import { get } from '@/utils/http/axios';// 简单GET请求
const data = await get({url: '/api/users',params: { page: 1, size: 10 }
});// 带配置的GET请求
const data = await get({url: '/api/config',params: { type: 'system' }
}, {retry: 3,cache: true,cacheExpire: 10 * 60 * 1000
});
POST请求
import { post } from '@/utils/http/axios';// 简单POST请求
const result = await post({url: '/api/users',data: { name: 'John', age: 30 }
});// 带配置的POST请求
const result = await post({url: '/api/users',data: userData
}, {retry: 2,showLoading: true
});
PUT请求
import { put } from '@/utils/http/axios';const result = await put({url: '/api/users/123',data: { name: 'John Updated' }
}, {retry: 1
});
DELETE请求
import { del } from '@/utils/http/axios';const result = await del({url: '/api/users/123'
}, {retry: 1
});
- 文件操作使用
文件上传
import { upload } from '@/utils/http/axios';// 单文件上传
const formData = new FormData();
formData.append('file', file);
const result = await upload({url: '/api/upload',data: formData
}, {showLoading: true
});// 多文件上传
const formData = new FormData();
files.forEach(file => {formData.append('files', file);
});
const result = await upload({url: '/api/upload/multiple',data: formData
});
文件下载
import { download } from '@/utils/http/axios';// 简单下载
const blob = await download({url: '/api/download/file.pdf',method: 'get'
});// 带参数的下载
const blob = await download({url: '/api/download',method: 'post',data: { fileId: '123' }
}, {showLoading: true,retry: 1
});// 下载并保存文件
const blob = await download({url: '/api/download/report.xlsx',method: 'post',data: { reportId: '456' }
});// 创建下载链接
const url = window.URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = 'report.xlsx';
link.click();
window.URL.revokeObjectURL(url);
- 响应格式使用
标准格式(默认)
// 返回 {code: 0, data: xxx, message: 'success'}
const result = await post({url: '/api/users',data: userData
}, {responseFormat: 'standard' // 默认值
});if (result.code === 0) {const data = result.data;
}
直接格式
// 直接返回 response.data
const data = await get({url: '/api/config'
}, {responseFormat: 'direct'
});
自动格式(推荐)
// 智能判断:有code字段按标准格式处理,否则直接返回数据
const permissions = await get({url: '/api/permissions'
}, {responseFormat: 'auto'
});// 如果返回 {code: 0, data: [...]} 则自动提取 data
// 如果直接返回 [...] 则直接使用
- 缓存使用
启用缓存
// 自动缓存GET请求
const data = await get({url: '/api/config'
}, {cache: true,cacheExpire: 5 * 60 * 1000 // 缓存5分钟
});// 第二次调用会使用缓存
const cachedData = await get({url: '/api/config'
}, {cache: true
});
清除缓存
import { clearCache } from '@/utils/http/axios';// 清除所有缓存
clearCache();// 清除特定缓存
clearCache('get:/api/config');
- 重试机制使用
基础重试
const data = await get({url: '/api/users'
}, {retry: 3, // 重试3次retryDelay: 1000 // 每次间隔1秒
});
不同场景的重试配置
// 重要数据,多重重试
const userData = await get({url: '/api/user/profile'
}, {retry: 5,retryDelay: 2000
});// 文件下载,少量重试
const blob = await download({url: '/api/download/file'
}, {retry: 1,retryDelay: 3000
});// 配置数据,不重试
const config = await get({url: '/api/config'
}, {retry: 0,cache: true
});
- 请求取消使用
取消单个请求
import { cancelRequest } from '@/utils/http/axios';// 发起请求
const requestKey = `get:/api/users:${Date.now()}`;
const data = await get({url: '/api/users',requestKey
});// 取消请求
cancelRequest(requestKey);
取消所有请求
import { cancelAllRequests } from '@/utils/http/axios';// 在组件销毁时取消所有请求
export default {beforeDestroy() {cancelAllRequests();}
}// 在页面切换时取消
window.addEventListener('beforeunload', () => {cancelAllRequests();
});
- 错误处理使用
try-catch处理
try {const data = await get({url: '/api/users'});
} catch (error) {if (error.response) {// 服务器错误console.error('服务器错误:', error.response.status);} else if (error.request) {// 网络错误console.error('网络连接失败');} else {// 其他错误console.error('请求配置错误:', error.message);}
}
Promise处理
get({url: '/api/users'
}).then(data => {console.log('成功:', data);
}).catch(error => {console.error('失败:', error);
});
- API层使用示例
业务接口调用
import { getUsers, addSalt, downloadFile } from '@/api/service';// 获取用户列表(带缓存)
const users = await getUsers('admin', false, {cache: true,cacheExpire: 10 * 60 * 1000
});// 添加Salt(带重试)
const result = await addSalt(saltData, {retry: 3,showLoading: true
});// 下载文件(带进度)
const blob = await downloadFile(subTaskId, {showLoading: true
});
权限接口调用
import { getOperations, getUserName } from '@/api/common-plat';// 获取权限(自动格式)
const permissions = await getOperations();// 获取用户名(自动格式)
const username = await getUserName();
- 高级配置使用
自定义配置
// 全局配置
import { setTimeout, setHeaders } from '@/utils/http/axios';// 设置超时时间
setTimeout(30000);// 设置请求头
setHeaders({'Custom-Header': 'value','Authorization': 'Bearer token'
});
组合配置
const advancedOptions = {retry: 3,retryDelay: 2000,cache: true,cacheExpire: 10 * 60 * 1000,responseFormat: 'auto',showLoading: true
};const data = await get({url: '/api/important-data'
}, advancedOptions);
- 实际项目使用场景
页面初始化
export default {async mounted() {try {// 并行加载配置数据const [clouds, permissions, userInfo] = await Promise.all([getClouds({ cache: true }),getOperations({ cache: true }),getUserName({ cache: true })]);this.clouds = clouds;this.permissions = permissions;this.userInfo = userInfo;} catch (error) {this.$message.error('初始化失败');}}
}
表单提交
async submitForm() {try {this.loading = true;const result = await addSalt(this.formData, {retry: 2,showLoading: false // 使用自定义loading});this.$message.success('添加成功');this.$emit('success');} catch (error) {this.$message.error(error.message || '添加失败');} finally {this.loading = false;}
}
文件下载
async downloadReport() {try {const blob = await downloadFile(this.reportId, {showLoading: true});// 保存文件const url = window.URL.createObjectURL(blob);const link = document.createElement('a');link.href = url;link.download = `report_${Date.now()}.xlsx`;link.click();window.URL.revokeObjectURL(url);this.$message.success('下载成功');} catch (error) {this.$message.error('下载失败');}
}
- 最佳实践总结
配置建议
// 配置类接口:启用缓存,不重试
const configOptions = {cache: true,cacheExpire: 5 * 60 * 1000,retry: 0
};// 业务接口:启用重试,不缓存
const businessOptions = {retry: 2,retryDelay: 1000,cache: false
};// 文件操作:少量重试,显示进度
const fileOptions = {retry: 1,retryDelay: 2000,showLoading: true
};
错误处理建议
// 统一错误处理
const handleApiError = (error) => {if (error.response?.status === 401) {// 跳转登录router.push('/login');} else if (error.response?.status === 403) {this.$message.error('权限不足');} else {this.$message.error(error.message || '操作失败');}
};
这些使用方法涵盖了axios封装的所有功能,可以根据具体需求选择合适的配置和调用方式!