目录
-
核心特性
-
安装配置
-
基础使用
-
高级功能
-
错误处理
-
拦截器机制
-
请求取消
-
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; // 5MB
const 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
});
}
}