Appearance
Axios 网络请求库与工程化封装指南
本文全面、系统地介绍现代前端主流 HTTP 库 Axios 的核心概念、请求配置参数、参数发送格式、拦截器工作原理、高级取消请求与生产级工程化单例封装。
1. Axios 概述与核心特性
Axios 是一个基于 Promise 的 HTTP 客户端,同时支持在浏览器和 Node.js 环境中运行(同构网络库)。
核心特性
- 同构跨平台:在浏览器端底层基于
XMLHttpRequest发送请求;在 Node.js 端底层基于原生http/https模块。 - 自动转换 JSON 数据:自动将响应的 JSON 字符串转为 JavaScript 对象,向服务端发送 POST 请求时自动将 JS 对象序列化为 JSON 字符串。
- 强大的拦截器体系:支持全局注册 请求拦截器 (Request Interceptors) 与 响应拦截器 (Response Interceptors)。
- 防止 CSRF:支持设置客户端自动携带跨站请求伪造 Token。
- 取消请求机制:基于原生的
AbortController优雅取消未完成的网络请求。
2. Axios 基础 API 与请求方式
2.1 常用请求别名方法
javascript
// 1. GET 请求:带 URL 查询参数 (?page=1&pageSize=10)
axios.get('/api/users', {
params: { page: 1, pageSize: 10 }
})
.then(response => console.log(response.data))
.catch(error => console.error(error));
// 2. POST 请求:提交 JSON 格式数据
axios.post('/api/users', {
username: 'Alice',
email: 'alice@example.com'
})
.then(response => console.log(response.data));
// 3. PUT 请求:更新数据
axios.put('/api/users/101', { username: 'AliceUpdated' });
// 4. DELETE 请求:删除数据
axios.delete('/api/users/101');3. 请求参数发送格式 (Content-Type)
不同后端接口对请求数据的格式要求有所不同,Axios 提供了对多种格式的支持:
3.1 JSON 格式(最常用,application/json)
直接将 JS 对象传给 data,Axios 默认将 Header 设置为 application/json:
javascript
axios.post('/api/data', { id: 1, name: 'Test' });3.2 Form 表单格式 (application/x-www-form-urlencoded)
可以使用 URLSearchParams 进行传参:
javascript
const params = new URLSearchParams();
params.append('username', 'admin');
params.append('password', '123456');
axios.post('/api/login', params);3.3 文件上传 (multipart/form-data)
上传图片或文件时,需要使用原生 FormData 对象:
javascript
const formData = new FormData();
formData.append('avatar', fileInput.files[0]); // 文件对象
formData.append('userId', '1001');
axios.post('/api/upload', formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
});4. 拦截器 (Interceptors) 原理与链式调用
拦截器是 Axios 最强大的功能之一。请求发起时先经过请求拦截器,接收响应时先经过响应拦截器:
[ 发起请求 ] ──> [ 请求拦截器 (注入Token/加签) ] ──> [ 发送到服务器 ]
│
[ 返回页面 ] <── [ 响应拦截器 (解包/统一错误提示) ] <─── [ 收到服务器响应 ]javascript
// 添加请求拦截器
axios.interceptors.request.use(config => {
// 在发送请求之前做些什么
config.headers.Authorization = 'Bearer token_abc123';
return config;
}, error => {
return Promise.reject(error);
});
// 添加响应拦截器
axios.interceptors.response.use(response => {
// 对响应数据做点什么
return response.data; // 直接解包返回 data
}, error => {
// 对响应错误做点什么
return Promise.reject(error);
});5. 生产级 Axios 工程化单例封装实践
在企业级前端项目(Vue3 / React)中,我们通常建立一个模块化的 HTTP 工具包:
javascript
// src/utils/request.js
import axios from 'axios';
// 1. 创建 Axios 单例
const request = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL || '/api', // 环境变量配置接口地址
timeout: 10000, // 请求超时时间 (10秒)
headers: {
'Content-Type': 'application/json;charset=UTF-8'
}
});
// 2. 请求拦截器:自动注入 Authorization Token
request.interceptors.request.use(
(config) => {
const token = localStorage.getItem('ACCESS_TOKEN');
if (token) {
config.headers['Authorization'] = `Bearer ${token}`;
}
return config;
},
(error) => Promise.reject(error)
);
// 3. 响应拦截器:统一解包与全局错误提示
request.interceptors.response.use(
(response) => {
const { code, message, data } = response.data;
// 假设服务端约定的成功业务码 code === 200
if (code === 200) {
return data;
}
// 处理特殊业务错误码(如 401 登录已过期)
if (code === 401) {
localStorage.removeItem('ACCESS_TOKEN');
window.location.href = '/login';
}
console.error(`业务异常 [${code}]: ${message}`);
return Promise.reject(new Error(message || 'Error'));
},
(error) => {
// 统一处理 HTTP 状态码异常
let errorMessage = '网络繁忙,请稍后再试';
if (error.response) {
const status = error.response.status;
switch (status) {
case 400: errorMessage = '请求参数错误 (400)'; break;
case 403: errorMessage = '拒绝访问,无权限 (403)'; break;
case 404: errorMessage = '请求的资源不存在 (404)'; break;
case 500: errorMessage = '服务器内部致命错误 (500)'; break;
}
} else if (error.message.includes('timeout')) {
errorMessage = '网络请求超时,请检查网络连接';
}
alert(errorMessage);
return Promise.reject(error);
}
);
export default request;6. 取消请求与防止重复提交
在搜索框联想或频繁切换 Tab 页时,旧的未完成请求可能会覆盖新请求的数据。使用原生的 AbortController 可以取消未完成的请求:
javascript
let controller = null;
function fetchSearchResults(keyword) {
// 1. 如果已有正在进行的请求,立即取消它
if (controller) {
controller.abort();
}
// 2. 新建 AbortController 实例
controller = new AbortController();
// 3. 将 signal 信号传入请求配置中
axios.get('/api/search', {
params: { q: keyword },
signal: controller.signal
})
.then(response => {
console.log('搜索结果:', response.data);
})
.catch(error => {
if (axios.isCancel(error)) {
console.log('上一请求已被成功取消');
} else {
console.error('请求出错:', error);
}
});
}