在前端开发中,HTTP 请求是与后端交互的核心环节。axios 作为当前最流行的 HTTP 客户端之一,凭借其简洁的 API、完善的功能和良好的兼容性,成为 Vue、React 等框架的首选请求工具。本文将从基础入门到高级实战,带你全方位掌握 axios 的使用技巧。
一、入门篇:认识 axios 并实现基础请求
1.1 什么是 axios?
axios 是一个基于 Promise 的 HTTP 客户端,支持浏览器和 Node.js 环境,主要特点包括:
-
支持 GET、POST 等所有 HTTP 请求方法
-
拦截请求和响应
-
自动转换 JSON 数据
-
取消请求
-
超时设置
-
错误处理
-
客户端防御 XSRF 攻击
1.2 安装与引入
方式 1:CDN 引入(快速测试)
<!-- 开发版(含调试信息) -->
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<!-- 生产版(压缩优化) -->
<script src="https://cdn.jsdelivr.net/npm/axios@1.6.2/dist/axios.min.js"></script>
方式 2:npm/yarn 安装(项目开发)
# npm
npm install axios --save
# yarn
yarn add axios
在项目中引入:
// ES6模块
import axios from 'axios';
// CommonJS
const axios = require('axios');
1.3 基础请求实现
1.3.1 GET 请求(获取数据)
无参数请求:
// 方式1:直接传入URL
axios.get('https://api.example.com/users')
.then(response => {
console.log('请求成功:', response.data)
}).catch(error => {
console.error('请求失败:', error)
})
// 方式2:使用async/await(推荐,代码更简洁)
async function getUserList () {
try {
const response = await axios.get('https://api.example.com/users')
console.log('用户列表:', response.data)
return response.data
} catch (error) {
console.error('获取用户失败:', error.message)
throw error // 如需上层处理,可抛出错误
}
}
带参数请求:
// 方式1:URL拼接参数
axios.get('https://api.example.com/users?id=123')
// 方式2:通过params配置(推荐,自动编码特殊字符)
axios.get('https://api.example.com/users', {
params: {
id: 123,
status: 'active',
page: 1,
size: 10
}
}).then(response => console.log(response.data)).catch(error => console.error(error))
1.3.2 POST 请求(提交数据)
主要用于提交表单、创建资源等场景,常用application/json格式(默认):
async function createUser () {
const userData = {
name: '张三',
age: 25,
email: 'zhangsan@example.com'
}
try {
const response = await axios.post('https://api.example.com/users', userData, {
headers: {
'Content-Type': 'application/json' // 默认已设置,可省略
}
})
console.log('用户创建成功:', response.data)
} catch (error) {
console.error('创建用户失败:', error)
}
}
表单提交(application/x-www-form-urlencoded):
// 方式1:手动转换
import qs from 'qs' // 需要安装qs:npm install qs
async function submitForm () {
const formData = { username: 'admin', password: '123456' }
const response = await axios.post(
'https://api.example.com/login',
qs.stringify(formData), // 转换为key=value格式
{ headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }
)
console.log('登录成功:', response.data)
}
// 方式2:使用FormData(文件上传常用)
async function uploadFile (file) {
const formData = new FormData()
formData.append('file', file)
formData.append('description', '文档上传')
const response = await axios.post(
'https://api.example.com/upload',
formData // FormData会自动设置Content-Type
)
console.log('上传成功:', response.data)
}
1.4 响应结构解析
axios 请求成功后返回的response对象包含以下核心属性:
{
data: { }, // 后端返回的响应数据(自动解析JSON)
status: 200, // HTTP状态码(200=成功,404=未找到,500=服务器错误等)
statusText: 'OK', // 状态文本描述
headers: { }, // 响应头信息
config: { }, // 本次请求的配置信息(URL、方法、参数等)
request: { } // 原生请求对象(浏览器中是XMLHttpRequest,Node.js中是http.ClientRequest)
}
二、进阶篇:核心功能实战
2.1 请求拦截器与响应拦截器
拦截器可对请求 / 响应进行统一处理,如添加 token、统一错误提示等,避免重复代码。
2.1.1 请求拦截器(处理请求前逻辑)
// 创建请求拦截器
axios.interceptors.request.use(
// 请求成功拦截(配置修改)
config => {
// 1. 添加Token(登录后常用)
const token = localStorage.getItem('token')
if (token) {
config.headers.Authorization = `Bearer ${token}`
}
// 2. 设置超时时间(全局统一)
config.timeout = 10000 // 10秒超时
// 3. 统一添加基础路径(也可通过defaults设置)
config.baseURL = 'https://api.example.com'
return config
},
// 请求错误拦截(如参数错误)
error => {
console.error('请求配置错误:', error)
return Promise.reject(error) // 必须返回rejected状态的Promise
}
)
2.1.2 响应拦截器(处理响应后逻辑)
// 创建响应拦截器
axios.interceptors.response.use(
// 响应成功拦截(状态码2xx/3xx)
response => {
// 可对响应数据进行统一处理(如剥离外层包装)
// 例:后端返回格式为 { code: 200, message: "成功", data: {} }
if (response.data.code === 200) {
return response.data.data // 直接返回核心数据,简化上层使用
}
return response.data
},
// 响应错误拦截(状态码4xx/5xx或网络错误)
error => {
// 1. 处理网络错误
if (!error.response) {
alert('网络异常,请检查网络连接!')
return Promise.reject(new Error('网络错误'))
}
// 2. 处理HTTP错误状态码
const status = error.response.status
switch (status) {
case 401: // 未授权(Token过期或无效)
alert('登录已过期,请重新登录!')
localStorage.removeItem('token') // 清除无效Token
window.location.href = '/login' // 跳转登录页
break
case 403: // 权限不足
alert('您没有操作权限!')
break
case 404: // 资源未找到
alert('请求的资源不存在!')
break
case 500: // 服务器错误
alert('服务器内部错误,请稍后重试!')
break
default:
alert(`请求错误(${status})`)
}
return Promise.reject(error)
}
)
2.1.3 移除拦截器
如需临时禁用拦截器,可保存拦截器 ID 并移除:
// 保存请求拦截器ID
const requestInterceptor = axios.interceptors.request.use(config => config)
// 移除请求拦截器
axios.interceptors.request.eject(requestInterceptor)
// 同理移除响应拦截器
const responseInterceptor = axios.interceptors.response.use(res => res)
axios.interceptors.response.eject(responseInterceptor)
2.2 并发请求处理
当需要同时发送多个请求并等待所有请求完成后再处理时,可使用axios.all和axios.spread(或 ES6 的Promise.all)。
方式 1:axios.all + axios.spread
// 定义两个请求
const request1 = axios.get('/users')
const request2 = axios.get('/posts')
// 并发执行
axios.all([request1, request2]).then(
axios.spread((usersResponse, postsResponse) => {
// 所有请求成功后执行
console.log('用户数据:', usersResponse.data)
console.log('文章数据:', postsResponse.data)
})
).catch(error => {
console.error('至少一个请求失败:', error)
})
方式 2:Promise.all(更通用,推荐)
async function fetchMultipleData () {
try {
const [usersData, postsData] = await Promise.all([
axios.get('/users'),
axios.get('/posts')
])
console.log('用户数据:', usersData.data)
console.log('文章数据:', postsData.data)
} catch (error) {
console.error('并发请求失败:', error)
}
}
2.3 取消请求
在某些场景下(如用户快速切换页面、搜索框输入防抖),需要取消未完成的请求,避免无效请求占用资源。
方式 1:使用 CancelToken(旧版,Axios < 0.22.0)
// 创建取消令牌生成器
const CancelToken = axios.CancelToken;
let cancel; // 用于保存取消函数
// 发送请求并绑定取消令牌
axios
.get("/users", {
cancelToken: new CancelToken(function executor(c) {
cancel = c; // 将取消函数赋值给外部变量
}),
})
.then((res) => console.log(res.data))
.catch((error) => {
if (axios.isCancel(error)) {
console.log("请求已取消:", error.message);
} else {
console.error("请求失败:", error);
}
});
// 取消请求(如用户点击“取消”按钮时)
cancel("用户主动取消请求");
方式 2:使用 AbortController(新版,Axios ≥ 0.22.0,推荐)
AbortController 是浏览器原生 API,更标准且支持取消多个请求:
// 创建控制器
const controller = new AbortController();
const signal = controller.signal; // 获取信号对象
// 发送请求(绑定信号)
axios
.get("/users", { signal })
.then((res) => console.log(res.data))
.catch((error) => {
if (error.name === "CanceledError") {
console.log("请求已取消");
} else {
console.error("请求失败:", error);
}
});
// 取消请求
controller.abort();
// 取消多个请求(共用同一个signal)
axios.get("/posts", { signal }); // 此请求也会被上面的abort()取消
三、高级篇:深度定制与最佳实践
3.1 创建自定义 axios 实例
当项目中存在多个后端服务(如 API 服务、文件服务),或需要不同的请求配置时,可创建多个自定义实例,避免全局配置冲突。
// 创建自定义实例
const apiInstance = axios.create({
baseURL: "https://api.example.com", // 基础路径
timeout: 15000, // 超时时间
headers: {
"Content-Type": "application/json",
"X-Request-From": "web", // 自定义请求头(标识请求来源)
},
});
// 为自定义实例添加拦截器
apiInstance.interceptors.request.use((config) => {
const token = localStorage.getItem("token");
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
});
// 使用自定义实例发送请求
async function getArticle(id) {
try {
const response = await apiInstance.get(`/articles/${id}`);
return response.data;
} catch (error) {
console.error("获取文章失败:", error);
}
}
// 再创建文件服务实例(不同配置)
const fileInstance = axios.create({
baseURL: "https://file.example.com",
timeout: 30000, // 文件上传超时时间更长
headers: { "Content-Type": "multipart/form-data" },
});
3.2 错误处理最佳实践
3.2.1 错误分类处理
axios 的错误主要分为三类,需针对性处理:
-
网络错误:无响应(如断网、跨域错误)
-
HTTP 错误:响应状态码 4xx/5xx
-
业务错误:状态码 200,但后端返回错误(如
code: 5001)
async function requestWithErrorHandle(url, config = {}) {
try {
const response = await axios(url, config);
// 处理业务错误(假设后端返回 { code, message, data })
if (response.data.code !== 200) {
throw new Error(`业务错误:${response.data.message}`);
}
return response.data.data;
} catch (error) {
// 1. 网络错误
if (!error.response) {
console.error("网络错误:", error.message);
return { success: false, message: "网络异常,请检查连接" };
}
// 2. HTTP错误
const { status, statusText } = error.response;
console.error(`HTTP错误:${status} ${statusText}`);
let message = `请求失败(${status})`;
if (status === 401) message = "登录已过期,请重新登录";
if (status === 403) message = "权限不足,无法操作";
if (status === 500) message = "服务器繁忙,请稍后重试";
// 3. 业务错误(已在try中抛出)
if (error.message.startsWith("业务错误:")) {
message = error.message.slice(6);
}
return { success: false, message };
}
}
3.2.2 错误重试机制
对于偶发性错误(如网络波动、服务器临时不可用),可实现自动重试功能:
// 带重试的请求函数
async function requestWithRetry(url, config = {}, retryCount = 2) {
try {
return await axios(url, config);
} catch (error) {
// 仅对5xx服务器错误和网络错误重试
if (
retryCount > 0 &&
(!error.response ||
(error.response.status >= 500 && error.response.status < 600))
) {
console.log(`请求失败,正在重试(剩余${retryCount}次)`);
// 重试前等待1秒(避免频繁重试)
await new Promise((resolve) => setTimeout(resolve, 1000));
return requestWithRetry(url, config, retryCount - 1);
}
// 重试次数用尽或非可重试错误,抛出错误
throw error;
}
}
// 使用
requestWithRetry("/data", { method: "GET" })
.then((res) => console.log(res.data))
.catch((error) => console.error("最终请求失败:", error));
3.3 与 TypeScript 结合(类型安全)
在 TS 项目中使用 axios 时,可通过接口定义请求参数和响应数据的类型,提升代码可维护性。
// 1. 定义响应数据类型
interface ApiResponse<T> {
code: number;
message: string;
data: T;
}
// 2. 定义业务数据类型
interface User {
id: number;
name: string;
email: string;
status: "active" | "inactive";
}
// 3. 带类型的请求函数
async function getUserById(id: number): Promise<User> {
const response: ApiResponse<User> = await axios.get(`/users/${id}`);
if (response.code !== 200) {
throw new Error(`获取用户失败:${response.message}`);
}
return response.data;
}
// 4. 使用(自动提示类型)
getUserById(123).then((user) => {
console.log(user.name); // 类型安全,不会报错
});
3.4 配置优先级
axios 的配置有三个层级,优先级从高到低为:
-
请求配置(单次请求时传入的 config)
-
实例配置(create 创建实例时的 config)
-
全局默认配置(axios.defaults)
// 1. 全局默认配置
axios.defaults.baseURL = "https://default.example.com";
axios.defaults.timeout = 5000;
// 2. 实例配置(覆盖全局默认)
const instance = axios.create({
baseURL: "https://instance.example.com",
timeout: 10000,
});
// 3. 请求配置(覆盖实例配置)
instance.get("/data", {
timeout: 15000, // 最终生效的超时时间为15000ms
});
四、总结与最佳实践
-
优先使用 async/await:相比.then (),代码更简洁,错误处理更直观
-
统一拦截器管理:在项目入口处配置全局拦截器,避免重复代码
-
创建自定义实例:多服务场景下,用实例隔离不同配置
-
合理设置超时:根据业务场景设置(普通请求 10s,文件上传 30s+)
-
取消无效请求:搜索、分页切换时取消前一次请求,减少资源浪费
-
完善错误处理:区分网络错误、HTTP 错误、业务错误,给用户友好提示
-
类型安全(TS 项目):定义请求 / 响应类型,提升代码可维护性
axios 作为前端请求的核心工具,掌握其从基础到高级的用法,能大幅提升接口交互的效率和稳定性。建议在实际项目中结合业务场景灵活运用,形成适合自身项目的请求封装方案。


492

被折叠的 条评论
为什么被折叠?



