现axios封装
javascript
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封装分析报告
- 优点分析
基础配置合理
javascript
axios.defaults.timeout = 100000; // 100秒超时,适合大文件下载
axios.defaults.withCredentials = true; // 支持跨域携带cookie
请求拦截器功能完善
javascript
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;
});
下载进度支持
javascript
const addDownloadProgress = (progressEvent) => {
if (progressEvent.lengthComputable) {
window.isFileDownloading = progressEvent.loaded !== progressEvent.total;
}
};
- 存在的问题
严重问题 - 响应拦截器过于简单
javascript
axiosInstance.interceptors.response.use(
(response) => (response.status === 200 ? response : response), // 逻辑冗余
(error) => {
const { response } = error;
return response ? Promise.reject(response.data) : Promise.reject(error);
}
);
问题:
没有统一的错误处理
没有统一的成功响应格式处理
没有网络错误、超时等特殊情况的处理
- 请求函数设计不合理
javascript
const request = (config) => {
// ...
return new Promise((resolve) => { // 只resolve,不reject
axiosInstance.request(conf).then((res) => {
resolve(res.data instanceof Blob ? res : res.data);
});
});
};
问题:
使用Promise包装axios,但只处理resolve,不处理reject
错误处理不完整
可能导致Promise永远pending
- 参数编码逻辑有缺陷
javascript
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值
-
改进建议
-
完善响应拦截器
javascript
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);
}
}
);
- 重构请求函数
javascript
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;
}
};
- 优化参数处理
javascript
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;
}
};
- 添加请求重试机制
javascript
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封装在基础功能上做得不错,但在错误处理和用户体验方面还有很大改进空间。
加强版本
javascript
/**
* 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) {
// 文件下载,直接返回response
result = 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. 智能重试机制
javascript
// 自动重试失败的请求
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. 智能缓存系统
javascript
// 自动缓存GET请求
const clouds = await getClouds({
cache: true, // 启用缓存
cacheExpire: 10 * 60 * 1000, // 缓存10分钟
});
// 缓存键自动生成
const cacheKey = `${method}:${url}:${JSON.stringify(params)}:${JSON.stringify(data)}`;
C. 多格式响应支持
javascript
// 标准格式:{code: 0, data: xxx}
const result = await addSalt(params);
// 直接格式:直接返回数据
const data = await getUsers('admin', { responseFormat: 'direct' });
// 自动格式:智能判断
const permissions = await getOperations(); // 自动处理权限数组
D. 请求取消功能
javascript
// 取消单个请求
import { cancelRequest } from '@/utils/http/axios';
cancelRequest('requestKey');
// 取消所有请求
import { cancelAllRequests } from '@/utils/http/axios';
cancelAllRequests();
// 组件销毁时自动取消
export default {
beforeDestroy() {
cancelAllRequests();
}
}
E. 文件下载优化
javascript
// 专门的下载方法
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. 基础使用
javascript
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. 高级配置
javascript
// 带重试和缓存的请求
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. 文件操作
javascript
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. 错误处理
javascript
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. 标准业务接口
javascript
// 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. 配置类接口
javascript
// 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. 权限接口
javascript
// 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. 缓存优化
javascript
// 配置接口自动缓存5分钟
const clouds = await getClouds(); // 第一次请求
const clouds2 = await getClouds(); // 使用缓存,不发送请求
B. 重试优化
javascript
// 网络不稳定时自动重试
const data = await getUsers('admin', { retry: 3 });
// 如果第一次失败,会自动重试3次
C. 请求取消
javascript
// 避免重复请求和内存泄漏
// 页面切换时自动取消未完成的请求
- 总结
优化后的axios封装提供了:
✅ 完整的错误处理 - 网络错误、服务器错误、业务错误
✅ 智能重试机制 - 自动重试失败的请求
✅ 智能缓存系统 - 自动缓存配置类接口
✅ 多格式响应支持 - 标准格式、直接格式、自动格式
✅ 请求取消功能 - 避免重复请求和内存泄漏
✅ 文件操作优化 - 专门的上传下载方法
✅ 详细日志记录 - 便于调试和监控
✅ 性能优化 - 缓存、重试、取消等机制
✅ 向后兼容 - 现有代码无需修改
✅ 易于扩展 - 模块化设计,便于添加新功能
这个封装大大提升了开发效率和用户体验,是现代Web应用HTTP请求处理的最佳实践!
使用方法
xios封装使用方法大全
- 基础HTTP方法使用
GET请求
javascript
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请求
javascript
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请求
javascript
import { put } from '@/utils/http/axios';
const result = await put({
url: '/api/users/123',
data: { name: 'John Updated' }
}, {
retry: 1
});
DELETE请求
javascript
import { del } from '@/utils/http/axios';
const result = await del({
url: '/api/users/123'
}, {
retry: 1
});
- 文件操作使用
文件上传
javascript
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
});
文件下载
javascript
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);
- 响应格式使用
标准格式(默认)
javascript
// 返回 {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;
}
直接格式
javascript
// 直接返回 response.data
const data = await get({
url: '/api/config'
}, {
responseFormat: 'direct'
});
自动格式(推荐)
javascript
// 智能判断:有code字段按标准格式处理,否则直接返回数据
const permissions = await get({
url: '/api/permissions'
}, {
responseFormat: 'auto'
});
// 如果返回 {code: 0, data: [...]} 则自动提取 data
// 如果直接返回 [...] 则直接使用
- 缓存使用
启用缓存
javascript
// 自动缓存GET请求
const data = await get({
url: '/api/config'
}, {
cache: true,
cacheExpire: 5 * 60 * 1000 // 缓存5分钟
});
// 第二次调用会使用缓存
const cachedData = await get({
url: '/api/config'
}, {
cache: true
});
清除缓存
javascript
import { clearCache } from '@/utils/http/axios';
// 清除所有缓存
clearCache();
// 清除特定缓存
clearCache('get:/api/config');
- 重试机制使用
基础重试
javascript
const data = await get({
url: '/api/users'
}, {
retry: 3, // 重试3次
retryDelay: 1000 // 每次间隔1秒
});
不同场景的重试配置
javascript
// 重要数据,多重重试
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
});
- 请求取消使用
取消单个请求
javascript
import { cancelRequest } from '@/utils/http/axios';
// 发起请求
const requestKey = `get:/api/users:${Date.now()}`;
const data = await get({
url: '/api/users',
requestKey
});
// 取消请求
cancelRequest(requestKey);
取消所有请求
javascript
import { cancelAllRequests } from '@/utils/http/axios';
// 在组件销毁时取消所有请求
export default {
beforeDestroy() {
cancelAllRequests();
}
}
// 在页面切换时取消
window.addEventListener('beforeunload', () => {
cancelAllRequests();
});
- 错误处理使用
try-catch处理
javascript
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处理
javascript
get({
url: '/api/users'
}).then(data => {
console.log('成功:', data);
}).catch(error => {
console.error('失败:', error);
});
- API层使用示例
业务接口调用
javascript
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
});
权限接口调用
javascript
import { getOperations, getUserName } from '@/api/common-plat';
// 获取权限(自动格式)
const permissions = await getOperations();
// 获取用户名(自动格式)
const username = await getUserName();
- 高级配置使用
自定义配置
javascript
// 全局配置
import { setTimeout, setHeaders } from '@/utils/http/axios';
// 设置超时时间
setTimeout(30000);
// 设置请求头
setHeaders({
'Custom-Header': 'value',
'Authorization': 'Bearer token'
});
组合配置
javascript
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);
- 实际项目使用场景
页面初始化
javascript
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('初始化失败');
}
}
}
表单提交
javascript
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;
}
}
文件下载
javascript
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('下载失败');
}
}
- 最佳实践总结
配置建议
javascript
// 配置类接口:启用缓存,不重试
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
};
错误处理建议
javascript
// 统一错误处理
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封装的所有功能,可以根据具体需求选择合适的配置和调用方式!