Axios全解析:从基础到高级实战技巧
目录
-
核心特性
-
安装配置
-
基础使用
-
高级功能
-
错误处理
-
拦截器机制
-
请求取消
-
TypeScript支持
-
最佳实践
-
常见问题
1. 核心特性
1.1 核心优势
-
全平台支持:浏览器 & Node.js 双环境
-
自动转换:JSON数据自动序列化
-
拦截器系统:请求/响应全链路控制
-
取消令牌:精准控制请求生命周期
-
防御性设计:XSRF 跨站攻击防护
-
进度跟踪:文件上传下载进度监控
1.2 性能对比
特性 | Axios | Fetch API |
---|---|---|
浏览器兼容性 | IE11+ | Chrome 42+ |
请求取消 | ✅ | 需AbortController |
超时设置 | 原生支持 | 需手动封装 |
拦截器 | 内置系统 | 需自行实现 |
上传进度 | 事件监听 | 不可用 |
2. 安装配置
2.1 安装方式
# NPM
npm install axios# Yarn
yarn add axios# CDN (浏览器环境)
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
2.2 全局配置
// 设置基准路径
axios.defaults.baseURL = 'https://api.yourdomain.com/v2';// 配置超时时间(毫秒)
axios.defaults.timeout = 10000; // 设置公共头信息
axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
3. 基础使用
3.1 发起请求
// GET请求(参数自动编码)
axios.get('/user', {params: {ID: 12345,role: 'admin'}
})// POST请求(自动序列化JSON)
axios.post('/user', {firstName: 'Fred',lastName: 'Flintstone'
})// 并发请求
const [userRes, orderRes] = await Promise.all([axios.get('/user/123'),axios.get('/orders?user=123')
]);
3.2 响应结构解析
{data: {}, // 响应主体status: 200, // HTTP状态码statusText: 'OK',headers: {}, // 响应头(自动格式化)config: {}, // 请求配置request: {} // 原始请求对象
}
4. 高级功能
4.1 创建实例
const apiClient = axios.create({baseURL: 'https://api.example.com',timeout: 5000,headers: {'X-Custom-Header': 'foobar'}
});// 使用实例
apiClient.get('/products');
4.2 文件上传(含进度)
const formData = new FormData();
formData.append('file', fileInput.files[0]);axios.post('/upload', formData, {headers: {'Content-Type': 'multipart/form-data'},onUploadProgress: progressEvent => {const percent = Math.round((progressEvent.loaded * 100) / progressEvent.total);console.log(`上传进度:${percent}%`);}
});
5. 错误处理
5.1 错误类型识别
axios.get('/user/123').catch(error => {if (error.response) {// 服务端响应异常(2xx外的状态码)console.log('服务器错误:', error.response.status);} else if (error.request) {// 请求已发送但无响应console.log('网络错误:', error.message);} else {// 配置错误console.log('配置错误:', error.message);}});
5.2 全局错误处理
// 响应拦截器统一处理
axios.interceptors.response.use(response => response,error => {const status = error.response?.status;if (status === 401) {window.location.href = '/login';} else if (status >= 500) {alert('服务器异常,请稍后重试');}return Promise.reject(error);}
);
6. 拦截器机制
6.1 请求拦截器
axios.interceptors.request.use(config => {// 添加认证令牌const token = localStorage.getItem('authToken');if (token) {config.headers.Authorization = `Bearer ${token}`;}// 添加时间戳防止缓存config.params = {...config.params,_t: Date.now()};return config;
});
6.2 响应拦截器
axios.interceptors.response.use(response => {// 统一处理业务状态码if (response.data.code !== 200) {return Promise.reject(response.data.msg);}return response.data;},error => {// 统一错误格式return Promise.reject({code: error.response?.status || 0,message: error.message});}
);
7. 请求取消
7.1 CancelToken方案(旧版)
const source = axios.CancelToken.source();axios.get('/user', {cancelToken: source.token
});// 取消请求
source.cancel('用户主动取消操作');
7.2 Fetch AbortController(推荐)
const controller = new AbortController();axios.get('/user', {signal: controller.signal
}).catch(err => {if (axios.isCancel(err)) {console.log('请求取消:', err.message);}
});// 取消请求
controller.abort('页面跳转取消');
8. TypeScript支持
8.1 响应类型定义
interface UserProfile {id: number;name: string;email: string;
}axios.get<UserProfile>('/user/123').then(response => {console.log(response.data.name); // 自动类型推断});
8.2 扩展默认配置
declare module 'axios' {interface AxiosRequestConfig {retry?: number; // 自定义重试配置showLoading?: boolean;}
}// 使用自定义配置
axios.get('/data', { retry: 3,showLoading: true
});
9. 最佳实践
9.1 分层架构
src/
├─ api/
│ ├─ auth.ts // 认证相关接口
│ ├─ product.ts // 商品模块接口
│ └─ index.ts // 统一导出
├─ utils/
│ └─ request.ts // Axios实例封装
9.2 安全实践
// CSRF防御
axios.defaults.xsrfCookieName = 'csrftoken';
axios.defaults.xsrfHeaderName = 'X-CSRFToken';// 速率限制
const rateLimitedAxios = axios.create();
let lastRequestTime = 0;rateLimitedAxios.interceptors.request.use(config => {const now = Date.now();if (now - lastRequestTime < 1000) {return Promise.reject(new Error('请求过于频繁'));}lastRequestTime = now;return config;
});
10. 常见问题
Q1: 如何防止重复提交?
const pendingRequests = new Map();axios.interceptors.request.use(config => {const requestKey = `${config.method}-${config.url}`;if (pendingRequests.has(requestKey)) {return Promise.reject(new Error('重复请求已阻止'));}pendingRequests.set(requestKey, true);config.complete = () => {pendingRequests.delete(requestKey);};return config;
});
Q2: 大文件分片上传?
async function uploadLargeFile(file) {const CHUNK_SIZE = 5 * 1024 * 1024; // 5MBconst totalChunks = Math.ceil(file.size / CHUNK_SIZE);for (let i = 0; i < totalChunks; i++) {const chunk = file.slice(i * CHUNK_SIZE, (i+1) * CHUNK_SIZE);await axios.post('/upload-chunk', {chunk,index: i,total: totalChunks,fileHash: file.hash});}
}
进阶资源
-
Axios官方文档
-
Axios源码解析
-
企业级封装示例