Axios 指南:现代前端 HTTP 请求库
前言
在现代前端开发中,HTTP 请求是必不可少的功能。Axios 作为一个基于 Promise 的网络请求库,已经成为前端开发者的首选工具。本文将全面介绍 Axios 的使用方法,从基础到高级,帮助你掌握这个强大的 HTTP 客户端库。
一、Axios 简介
1.1 什么是 Axios?
Axios 是一个基于 Promise 的网络请求库,可以同时运行在浏览器和 Node.js 环境中。它是 isomorphic 的(同构的),意味着同一套代码可以在浏览器和 Node.js 中运行。
- 浏览器端(客户端):使用 XMLHttpRequest
- Node.js 端(服务端):使用原生 http 模块
1.2 为什么选择 Axios?
相比原生的 fetch API 和 XMLHttpRequest,Axios 具有以下优势:
- 基于 Promise:天然支持 Promise,可以使用 async/await
- 自动转换 JSON:自动将请求和响应数据转换为 JSON
- 请求/响应拦截器:可以在请求发送前和响应接收后进行处理
- 取消请求:支持取消正在进行的请求
- 超时处理:内置超时处理机制
- 错误处理:更好的错误处理机制
- 并发请求:支持同时发送多个请求
- 请求进度:支持上传和下载进度监控
- 防御 XSRF:客户端支持防御跨站请求伪造
二、安装与引入
2.1 安装
使用 npm:
npm install axios
使用 yarn:
yarn add axios
使用 pnpm:
pnpm add axios
使用 CDN(浏览器环境):
<!-- jsDelivr CDN -->
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<!-- unpkg CDN -->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
2.2 引入方式
ES6 模块(推荐):
import axios from 'axios';
CommonJS:
const axios = require('axios');
浏览器全局变量:
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
// axios 作为全局变量使用
axios.get('/api/users')
.then(response => console.log(response.data));
</script>
三、基本用法
3.1 GET 请求
import axios from 'axios';
// 基本 GET 请求
axios.get('/api/users')
.then(response => {
console.log(response.data);
})
.catch(error => {
console.error(error);
});
// 带参数的 GET 请求
axios.get('/api/users', {
params: {
page: 1,
limit: 10,
keyword: '张三'
}
})
.then(response => {
console.log(response.data);
});
// 使用 async/await
async function fetchUsers() {
try {
const response = await axios.get('/api/users');
console.log(response.data);
return response.data;
} catch (error) {
console.error('获取用户失败:', error);
throw error;
}
}
3.2 POST 请求
// 基本 POST 请求
axios.post('/api/users', {
name: '张三',
email: 'zhangsan@example.com',
age: 25
})
.then(response => {
console.log('创建成功:', response.data);
})
.catch(error => {
console.error('创建失败:', error);
});
// 使用 async/await
async function createUser(userData) {
try {
const response = await axios.post('/api/users', userData);
return response.data;
} catch (error) {
console.error('创建用户失败:', error);
throw error;
}
}
// 发送 FormData
const formData = new FormData();
formData.append('name', '张三');
formData.append('avatar', fileInput.files[0]);
axios.post('/api/users', formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
});
3.3 PUT 和 PATCH 请求(开发中常见Get和Post)
// PUT 请求(完整更新)
axios.put('/api/users/1', {
name: '李四',
email: 'lisi@example.com',
age: 30
})
.then(response => {
console.log('更新成功:', response.data);
});
// PATCH 请求(部分更新)
axios.patch('/api/users/1', {
age: 31
})
.then(response => {
console.log('部分更新成功:', response.data);
});
3.4 DELETE 请求
// DELETE 请求
axios.delete('/api/users/1')
.then(response => {
console.log('删除成功');
})
.catch(error => {
console.error('删除失败:', error);
});
3.5 并发请求
// 使用 Promise.all 并发请求
async function fetchAllData() {
try {
const [users, posts, comments] = await Promise.all([
axios.get('/api/users'),
axios.get('/api/posts'),
axios.get('/api/comments')
]);
return {
users: users.data,
posts: posts.data,
comments: comments.data
};
} catch (error) {
console.error('获取数据失败:', error);
throw error;
}
}
// 使用 axios.all(Promise.all 的别名)
axios.all([
axios.get('/api/users'),
axios.get('/api/posts')
])
.then(axios.spread((usersRes, postsRes) => {
console.log('用户:', usersRes.data);
console.log('文章:', postsRes.data);
}));
四、请求配置
4.1 基本配置
// 使用配置对象发送请求
axios({
method: 'post',
url: '/api/users',
data: {
name: '张三',
email: 'zhangsan@example.com'
},
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer token123'
},
timeout: 5000, // 超时时间(毫秒)
params: {
// URL 参数
id: 123
}
});
4.2 常用配置选项
{
// 请求地址
url: '/api/users',
// 请求方法(默认 GET)
method: 'get',
// 请求基础 URL
baseURL: 'https://api.example.com',
// 请求头
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer token'
},
// URL 参数(仅适用于 GET 请求)
params: {
page: 1,
limit: 10
},
// 请求体数据(POST、PUT、PATCH)
data: {
name: '张三'
},
// 超时时间(毫秒)
timeout: 5000,
// 响应数据类型(默认 json)
responseType: 'json', // 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream'
// 请求凭证
withCredentials: false,
// 上传进度
onUploadProgress: function (progressEvent) {
const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total);
console.log('上传进度:', percentCompleted + '%');
},
// 下载进度
onDownloadProgress: function (progressEvent) {
const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total);
console.log('下载进度:', percentCompleted + '%');
}
}
五、响应结构
5.1 响应对象
axios.get('/api/users')
.then(response => {
// 响应对象结构
console.log(response.data); // 响应数据
console.log(response.status); // HTTP 状态码
console.log(response.statusText); // HTTP 状态消息
console.log(response.headers); // 响应头
console.log(response.config); // 请求配置
});
5.2 响应数据结构
{
data: {}, // 服务器返回的数据
status: 200, // HTTP 状态码
statusText: 'OK', // HTTP 状态消息
headers: {}, // 响应头
config: {}, // 请求配置
request: {} // 请求对象
}
六、错误处理
6.1 错误对象结构
axios.get('/api/users')
.catch(error => {
if (error.response) {
// 服务器返回了错误状态码 (4xx, 5xx)
console.error('错误状态码:', error.response.status);
console.error('错误数据:', error.response.data);
console.error('错误头:', error.response.headers);
} else if (error.request) {
// 请求已发出但没有收到响应
console.error('请求错误:', error.request);
} else {
// 其他错误
console.error('错误信息:', error.message);
}
console.error('错误配置:', error.config);
});
6.2 错误处理最佳实践
async function fetchData(url) {
try {
const response = await axios.get(url);
return response.data;
} catch (error) {
if (error.response) {
// 服务器返回了错误状态码
const { status, statusText, data } = error.response;
switch (status) {
case 400:
console.error('请求参数错误');
break;
case 401:
console.error('未授权,请重新登录');
// 可以在这里跳转到登录页
break;
case 403:
console.error('没有权限访问此资源');
break;
case 404:
console.error('请求的资源不存在');
break;
case 500:
console.error('服务器内部错误');
break;
default:
console.error(`请求失败 [${status}]: ${statusText}`);
}
return Promise.reject({
status,
message: data.message || statusText,
data
});
} else if (error.request) {
// 网络错误
console.error('网络错误:请求超时或无法连接到服务器');
return Promise.reject({
message: '网络错误,请检查网络连接'
});
} else {
// 其他错误
console.error('请求配置错误:', error.message);
return Promise.reject({
message: error.message
});
}
}
}
七、拦截器
7.1 请求拦截器
请求拦截器可以在请求发送前对请求进行处理,常用于添加 token、设置请求头等。
// 添加请求拦截器
axios.interceptors.request.use(
function (config) {
// 在发送请求之前做些什么
// 添加 token
const token = localStorage.getItem('token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
// 添加时间戳防止缓存
if (config.method === 'get') {
config.params = config.params || {};
config.params._t = Date.now();
}
// 显示加载提示
console.log('发送请求:', config.url);
return config;
},
function (error) {
// 对请求错误做些什么
return Promise.reject(error);
}
);
7.2 响应拦截器
响应拦截器可以在响应接收后对响应进行处理,常用于统一处理错误、格式化数据等。
// 添加响应拦截器
axios.interceptors.response.use(
function (response) {
// 对响应数据做点什么
// 统一处理响应数据格式
if (response.data.code === 200) {
return response.data.data;
} else {
return Promise.reject(new Error(response.data.message));
}
},
function (error) {
// 对响应错误做点什么
// 统一处理错误
if (error.response) {
const { status } = error.response;
if (status === 401) {
// 未授权,清除 token 并跳转到登录页
localStorage.removeItem('token');
window.location.href = '/login';
} else if (status === 403) {
// 没有权限
console.error('没有权限访问此资源');
} else if (status >= 500) {
// 服务器错误
console.error('服务器错误,请稍后重试');
}
}
return Promise.reject(error);
}
);
7.3 移除拦截器
// 创建拦截器
const myInterceptor = axios.interceptors.request.use(function () {/*...*/});
// 移除拦截器
axios.interceptors.request.eject(myInterceptor);
八、Axios 实例
8.1 创建实例
当需要为不同的 API 配置不同的 baseURL、timeout 等时,可以创建多个 axios 实例。
import axios from 'axios';
// 创建实例
const apiClient = axios.create({
baseURL: 'https://yourapi.com',
timeout: 5000,
headers: {
'Content-Type': 'application/json'
}
});
// 使用实例
apiClient.get('/users')
.then(response => {
console.log(response.data);
});
// 为实例添加拦截器
apiClient.interceptors.request.use(
config => {
config.headers.Authorization = `Bearer ${localStorage.getItem('token')}`;
return config;
}
);
8.2 多个实例示例
// API 客户端
const apiClient = axios.create({
baseURL: 'https://api.example.com',
timeout: 10000
});
// 文件上传客户端
const uploadClient = axios.create({
baseURL: 'https://upload.example.com',
timeout: 30000,
headers: {
'Content-Type': 'multipart/form-data'
}
});
// 第三方 API 客户端
const thirdPartyClient = axios.create({
baseURL: 'https://third-party-api.com',
timeout: 5000
});
九、取消请求
9.1 使用 AbortController(推荐)
// 创建 AbortController
const controller = new AbortController();
// 发送请求
axios.get('/api/users', {
signal: controller.signal
})
.then(response => {
console.log(response.data);
})
.catch(error => {
if (axios.isCancel(error)) {
console.log('请求已取消:', error.message);
} else {
console.error('请求失败:', error);
}
});
// 取消请求
controller.abort();
9.2 在组件中使用
// Vue 组件示例
export default {
data() {
return {
controller: null
};
},
methods: {
async fetchData() {
// 如果已有请求在进行,先取消
if (this.controller) {
this.controller.abort();
}
// 创建新的控制器
this.controller = new AbortController();
try {
const response = await axios.get('/api/users', {
signal: this.controller.signal
});
return response.data;
} catch (error) {
if (axios.isCancel(error)) {
console.log('请求已取消');
} else {
console.error('请求失败:', error);
}
}
}
},
beforeUnmount() {
// 组件卸载时取消请求
if (this.controller) {
this.controller.abort();
}
}
};
十、默认配置
10.1 全局默认配置
// 设置全局默认配置
axios.defaults.baseURL = 'https://api.example.com';
axios.defaults.timeout = 5000;
axios.defaults.headers.common['Authorization'] = 'Bearer token';
axios.defaults.headers.post['Content-Type'] = 'application/json';
10.2 实例默认配置
const instance = axios.create({
baseURL: 'https://api.example.com',
timeout: 5000
});
// 修改实例默认配置
instance.defaults.headers.common['Authorization'] = 'Bearer new-token';
10.3 配置优先级
配置的优先级从高到低:
- 请求配置(
config参数) - 实例默认配置(
instance.defaults) - 全局默认配置(
axios.defaults)
十一、实际应用示例
11.1 封装 Axios 工具类
// utils/request.js
import axios from 'axios';
import { message } from 'ant-design-vue'; // 或其他 UI 库的消息提示
// 创建 axios 实例
const service = axios.create({
baseURL: process.env.VUE_APP_API_BASE_URL,//从环境变量中获取
timeout: 10000
});
// 请求拦截器
service.interceptors.request.use(
config => {
// 添加 token
const token = localStorage.getItem('token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
error => {
console.error('请求错误:', error);
return Promise.reject(error);
}
);
// 响应拦截器
service.interceptors.response.use(
response => {
const res = response.data;
// 根据后端返回的数据结构进行处理
if (res.code !== 200) {
message.error(res.message || '请求失败');
// 特殊状态码处理
if (res.code === 401) {
// 未授权,跳转到登录页
localStorage.removeItem('token');
window.location.href = '/login';
}
return Promise.reject(new Error(res.message || '请求失败'));
} else {
return res.data;
}
},
error => {
console.error('响应错误:', error);
let errorMessage = '请求失败';
if (error.response) {
const { status, data } = error.response;
errorMessage = data.message || `请求失败 [${status}]`;
if (status === 401) {
localStorage.removeItem('token');
window.location.href = '/login';
}
} else if (error.request) {
errorMessage = '网络错误,请检查网络连接';
}
message.error(errorMessage);
return Promise.reject(error);
}
);
export default service;
11.2 API 接口封装(demo)
// api/user.js
import request from '@/utils/request';
// 获取用户列表
export function getUserList(params) {
return request({
url: '/users',
method: 'get',
params
});
}
// 获取用户详情
export function getUserDetail(id) {
return request({
url: `/users/${id}`,
method: 'get'
});
}
// 创建用户
export function createUser(data) {
return request({
url: '/users',
method: 'post',
data
});
}
// 更新用户
export function updateUser(id, data) {
return request({
url: `/users/${id}`,
method: 'put',
data
});
}
// 删除用户
export function deleteUser(id) {
return request({
url: `/users/${id}`,
method: 'delete'
});
}
11.3 在 Vue 组件中使用
// Vue 组件
import { getUserList, createUser } from '@/api/user';
export default {
data() {
return {
users: [],
loading: false
};
},
async mounted() {
await this.loadUsers();
},
methods: {
async loadUsers() {
this.loading = true;
try {
this.users = await getUserList({
page: 1,
limit: 10
});
} catch (error) {
console.error('加载用户失败:', error);
} finally {
this.loading = false;
}
},
async handleCreateUser(userData) {
try {
await createUser(userData);
this.$message.success('创建成功');
await this.loadUsers(); // 重新加载列表
} catch (error) {
console.error('创建用户失败:', error);
}
}
}
};
11.4 文件上传示例
// 上传单个文件
async function uploadFile(file) {
const formData = new FormData();
formData.append('file', file);
try {
const response = await axios.post('/api/upload', formData, {
headers: {
'Content-Type': 'multipart/form-data'
},
onUploadProgress: (progressEvent) => {
const percentCompleted = Math.round(
(progressEvent.loaded * 100) / progressEvent.total
);
console.log('上传进度:', percentCompleted + '%');
}
});
return response.data;
} catch (error) {
console.error('上传失败:', error);
throw error;
}
}
// 上传多个文件
async function uploadFiles(files) {
const formData = new FormData();
files.forEach((file, index) => {
formData.append(`files[${index}]`, file);
});
return axios.post('/api/upload/multiple', formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
});
}
十二、常见问题与最佳实践
12.1 常见问题
1. 如何处理 CORS 跨域问题?
// 后端需要设置 CORS 头
// 前端可以设置 withCredentials
在vite中找到vite.config.js配置server.proxy转发代理请求
2. 如何防止重复请求?
let pendingRequests = new Map();
function addPendingRequest(config) {
const requestKey = `${config.method}-${config.url}`;
config.cancelToken = config.cancelToken || axios.CancelToken.source();
if (pendingRequests.has(requestKey)) {
const cancel = pendingRequests.get(requestKey);
delete pendingRequests[requestKey];
cancel.cancel('重复请求已取消');
}
pendingRequests.set(requestKey, config.cancelToken);
}
function removePendingRequest(config) {
const requestKey = `${config.method}-${config.url}`;
if (pendingRequests.has(requestKey)) {
pendingRequests.delete(requestKey);
}
}
3. 如何实现请求重试?
async function requestWithRetry(url, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
const response = await axios.get(url);
return response.data;
} catch (error) {
if (i === maxRetries - 1) {
throw error;
}
// 等待后重试
await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
}
}
}
12.2 最佳实践
- 统一封装:创建统一的 axios 实例,配置 baseURL、timeout 等
- 使用拦截器:统一处理 token、错误等
- 错误处理:统一错误处理逻辑,提供友好的错误提示
- 类型安全:使用 TypeScript 定义请求和响应的类型
- 取消请求:在组件卸载时取消未完成的请求
- 请求缓存:对不经常变化的数据进行缓存
- 加载状态:使用拦截器统一管理加载状态
十三、总结
Axios 是一个功能强大、易于使用的 HTTP 客户端库,它提供了:
- ✅ 基于 Promise 的 API,支持 async/await
- ✅ 请求和响应拦截器
- ✅ 自动转换 JSON 数据
- ✅ 取消请求功能
- ✅ 超时处理
- ✅ 错误处理机制
- ✅ 支持浏览器和 Node.js
通过本文的学习,你应该能够:
- 理解 Axios 的基本概念和特性
- 掌握 Axios 的基本用法和高级特性
- 学会使用拦截器处理请求和响应
- 能够封装自己的 Axios 工具类
- 了解最佳实践和常见问题的解决方案
希望这篇文章能帮助你更好地使用 Axios 进行前端开发!
参考资源
如果这篇文章对你有帮助,欢迎点赞、收藏和分享!如有问题,欢迎在评论区留言讨论。