axios 基本操作
一、axios 概述
axios 是一个基于 Promise 的 HTTP 客户端库,用于浏览器和 Node.js 环境中发送网络请求。与原生 XMLHttpRequest 或 fetch 相比,axios 提供了更简洁的 API 和更强的功能。
核心优势:
- Promise 风格 :基于 Promise,支持
async/await语法,避免回调地狱。 - 自动转换 JSON :响应数据自动由 JSON 字符串转为 JavaScript 对象,无需手动调用
JSON.parse()。 - 拦截器:可在请求发出前或响应到达后统一处理(如添加 token、统一报错)。
- 取消请求 :通过
AbortController取消不再需要的请求。 - 超时控制 :内置
timeout参数,超过指定时间自动中断请求。 - 跨平台 :浏览器端基于
XMLHttpRequest,Node.js 端基于http模块,两套环境使用同一套 API。
二、安装与引入
安装
bash
# npm 项目中安装
npm install axios
html
<!-- 通过 CDN 直接引入(浏览器环境) -->
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
引入
js
// ES Module 方式(推荐,用于现代前端项目)
import axios from 'axios';
// CommonJS 方式(Node.js 环境)
const axios = require('axios');
引入 CDN 后,axios 会挂载为全局变量,可直接使用,无需额外配置。
三、基本请求方法
axios 支持所有 HTTP 方法,最常用的是 get、post、put、delete。
GET 请求
js
// 方式一:简写
async function getUsers() {
const response = await axios.get('https://api.example.com/users');
console.log(response.data);
}
// 方式二:完整写法(通过 config 对象指定 method)
async function getUsers2() {
const response = await axios({
method: 'get',
url: 'https://api.example.com/users',
});
console.log(response.data);
}
携带查询参数:
js
// 直接拼接在 URL 中
axios.get('https://api.example.com/users?id=1&status=active');
// 通过 params 参数传入(推荐,axios 会自动拼接到 URL 末尾)
axios.get('https://api.example.com/users', {
params: {
id: 1,
status: 'active',
},
});
// 实际请求地址:https://api.example.com/users?id=1&status=active
使用 params 对象的方式更清晰,也便于动态修改参数。
POST 请求
POST 用于向服务器提交数据(创建资源),数据放在请求体中。
js
// 方式一:简写
async function createUser() {
const response = await axios.post('https://api.example.com/users', {
name: '张三',
email: 'zhangsan@example.com',
age: 25,
});
console.log('创建成功', response.data);
}
// 方式二:完整写法
async function createUser2() {
const response = await axios({
method: 'post',
url: 'https://api.example.com/users',
data: {
name: '张三',
email: 'zhangsan@example.com',
age: 25,
},
});
console.log('创建成功', response.data);
}
要点:
- GET 请求的参数用
params,放在 URL 中。 - POST / PUT / PATCH 请求的参数用
data,放在请求体中。
PUT 请求
PUT 用于整体更新已有资源。
js
async function updateUser() {
const response = await axios.put('https://api.example.com/users/1', {
name: '张三(更新)',
email: 'zhangsan_new@example.com',
age: 26,
});
console.log('更新成功', response.data);
}
DELETE 请求
DELETE 用于删除资源。
js
async function deleteUser() {
const response = await axios.delete('https://api.example.com/users/1');
console.log('删除成功');
}
请求方法对照
| 方法 | 用途 | 传参方式 | 对应简写 |
|---|---|---|---|
| GET | 获取数据 | URL 查询参数 params |
axios.get() |
| POST | 创建资源 | 请求体 data |
axios.post() |
| PUT | 整体更新资源 | 请求体 data |
axios.put() |
| PATCH | 局部更新资源 | 请求体 data |
axios.patch() |
| DELETE | 删除资源 | URL 路径参数 | axios.delete() |
四、请求配置
除了 method 和 url,axios 支持丰富的配置项来定制请求行为。
常用请求头
js
axios.get('https://api.example.com/data', {
headers: {
'Authorization': 'Bearer your_token_here',
'Content-Type': 'application/json',
'X-Custom-Header': 'custom-value',
},
});
超时设置
js
axios.get('https://api.example.com/data', {
timeout: 5000, // 单位:毫秒,超过 5 秒未响应则中断并抛出错误
});
发送不同格式的数据
js
// JSON 格式(默认,Content-Type 自动设为 application/json)
axios.post('/api/data', {
key: 'value',
});
// 表单格式(Content-Type: application/x-www-form-urlencoded)
const params = new URLSearchParams();
params.append('username', 'admin');
params.append('password', '123456');
axios.post('/api/login', params);
// 文件上传(Content-Type: multipart/form-data)
const formData = new FormData();
formData.append('file', fileInput.files[0]);
formData.append('description', '头像图片');
axios.post('/api/upload', formData);
五、响应结构
axios 的响应对象包含以下字段:
js
async function inspectResponse() {
const response = await axios.get('https://api.example.com/users/1');
console.log(response.data); // 服务端返回的响应体数据(已被解析为对象)
console.log(response.status); // HTTP 状态码,如 200、404、500
console.log(response.statusText); // HTTP 状态文本,如 "OK"、"Not Found"
console.log(response.headers); // 响应头,为对象格式
console.log(response.config); // 本次请求所使用的配置对象
}
| 字段 | 类型 | 说明 |
|---|---|---|
data |
any | 响应体数据,自动根据 Content-Type 解析 |
status |
number | HTTP 状态码(200、201、404、500 等) |
statusText |
string | 状态码对应的文本描述 |
headers |
object | 响应头键值对 |
config |
object | 当前请求的完整配置 |
request |
object | 发起此次请求的底层对象(浏览器中为 XMLHttpRequest) |
实际使用中,response.data 是最常用的字段。
六、错误处理
axios 对 HTTP 状态码不在 2xx 范围内的响应均视为错误,会进入 catch 分支。
基本错误捕获
js
async function fetchWithErrorHandling() {
try {
const response = await axios.get('https://api.example.com/users/999');
console.log('成功', response.data);
} catch (error) {
// 推荐写法:先判断 error.response 是否存在
if (error.response) {
// 服务端返回了响应,但状态码不在 2xx 范围
console.log('状态码:', error.response.status); // 如 404
console.log('响应数据:', error.response.data); // 服务端返回的错误信息
} else if (error.request) {
// 请求已经发出但未收到响应(网络不通、超时等)
console.log('网络错误或无响应');
} else {
// 请求在发送前就出错了(如配置错误)
console.log('请求配置错误', error.message);
}
}
}
三类错误对应的场景:
| 错误类型 | 触发条件 | 判断方式 |
|---|---|---|
| 服务端错误 | 服务端返回了 4xx / 5xx 状态码 | error.response 存在 |
| 网络错误 | 请求已发出但未收到响应 | error.request 存在但 error.response 不存在 |
| 配置错误 | 请求配置有误,未能发出 | error.request 也不存在 |
async/await 中的错误处理
js
async function fetchUser(id) {
try {
const response = await axios.get(`https://api.example.com/users/${id}`);
console.log(response.data);
} catch (error) {
if (error.response) {
// 服务端返回了错误状态码
const status = error.response.status;
if (status === 404) {
console.error('用户不存在');
} else if (status === 500) {
console.error('服务器内部错误');
}
} else {
console.error('网络异常', error.message);
}
}
}
根据状态码统一处理
js
async function requestWithStatusHandling() {
try {
const response = await axios.get('/api/data');
console.log(response.data);
} catch (error) {
if (!error.response) return;
switch (error.response.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(`未知错误,状态码:${error.response.status}`);
}
}
}
七、拦截器
拦截器是 axios 最强大的特性之一,允许在请求发送前或响应到达 try/catch 处理逻辑前统一拦截。
请求拦截器
在请求发出前执行,常用于统一添加 token、设置 loading。
js
// 添加请求拦截器
axios.interceptors.request.use(
config => {
// 在发送请求前做些什么:例如从 localStorage 读取 token 并附加到请求头
const token = localStorage.getItem('token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
console.log('请求发出:', config.method.toUpperCase(), config.url);
return config; // 必须返回 config,否则请求会被阻塞
},
error => {
// 请求错误时的处理
return Promise.reject(error);
}
);
响应拦截器
在响应数据到达 await 调用处或 catch 分支之前执行,常用于统一处理错误提示、刷新 token。
js
// 添加响应拦截器
axios.interceptors.response.use(
response => {
// 对 2xx 范围内的响应做统一处理
// 例如:只返回 data,让调用方不用每次都写 .data
return response.data;
},
error => {
// 对超出 2xx 范围的响应做统一处理
if (error.response) {
const status = error.response.status;
if (status === 401) {
// token 过期,清除本地信息并跳转登录页
localStorage.removeItem('token');
window.location.href = '/login';
}
// 统一弹出错误提示
console.error(error.response.data.message || '请求失败');
}
return Promise.reject(error);
}
);
取消拦截器
js
const myInterceptor = axios.interceptors.request.use(config => {
// ...
return config;
});
// 在不需要时移除该拦截器
axios.interceptors.request.eject(myInterceptor);
八、实例与默认配置
当项目中需要访问多个不同域名的后端服务,或不同模块需要不同的超时时间时,可以创建独立的 axios 实例,避免污染全局默认配置。
创建实例
js
// 创建一个带默认配置的 axios 实例
const apiClient = axios.create({
baseURL: 'https://api.example.com', // 基础 URL,后续请求只需写路径
timeout: 10000, // 默认超时 10 秒
headers: {
'Content-Type': 'application/json',
},
});
// 使用实例发送请求,URL 会自动拼接 baseURL
apiClient.get('/users'); // 实际请求 https://api.example.com/users
apiClient.post('/users', { name: '李四' });
apiClient.put('/users/1', { name: '李四(更新)' });
apiClient.delete('/users/1');
多实例场景示例
js
// 业务 API
const businessAPI = axios.create({
baseURL: 'https://api.example.com/v1',
timeout: 5000,
});
// 文件上传服务(时间更长)
const uploadAPI = axios.create({
baseURL: 'https://upload.example.com',
timeout: 30000, // 上传给 30 秒
});
// 第三方 API
const thirdPartyAPI = axios.create({
baseURL: 'https://third-party-api.com',
timeout: 8000,
});
每个实例有独立的拦截器,互不干扰:
js
// 给业务 API 实例添加拦截器
businessAPI.interceptors.request.use(config => {
config.headers.Authorization = `Bearer ${getToken()}`;
return config;
});
// 上传实例不需要 token,不加该拦截器
修改全局默认配置
js
// 修改全局 axios 的默认配置
axios.defaults.baseURL = 'https://api.example.com';
axios.defaults.timeout = 5000;
axios.defaults.headers.common['Authorization'] = 'Bearer token_value';
axios.defaults.headers.post['Content-Type'] = 'application/json';
推荐使用实例而非修改全局默认值,避免不同模块的配置互相影响。
九、取消请求
在某些场景下(如用户快速切换页面、输入框防抖搜索),需要取消尚未完成的请求以节省资源。
js
// 创建 AbortController,在外面定义以便随时调用 abort()
const controller = new AbortController();
async function fetchWithCancel() {
try {
const response = await axios.get('https://api.example.com/search?q=abc', {
signal: controller.signal, // 传入 signal
});
console.log(response.data);
} catch (error) {
if (axios.isCancel(error)) {
console.log('请求已被取消', error.message);
} else {
console.error('请求出错', error);
}
}
}
// 发起请求(不 await,让它在后台执行)
fetchWithCancel();
// 在需要时取消请求(例如用户点击取消按钮时调用)
controller.abort();
搜索防抖示例:每次用户输入时取消上一个未完成的搜索请求。
js
let controller = null;
searchInput.addEventListener('input', async (e) => {
// 取消上一次未完成的请求
if (controller) {
controller.abort();
}
// 新建 controller
controller = new AbortController();
try {
const response = await axios.get('/api/search', {
params: { keyword: e.target.value },
signal: controller.signal,
});
renderResults(response.data);
} catch (error) {
if (!axios.isCancel(error)) {
console.error('搜索失败', error);
}
}
});
十、并发请求
当需要同时发送多个请求并等待全部完成后一起处理时,可使用 Promise.all。
js
async function loadDashboard() {
try {
const [usersRes, postsRes, statsRes] = await Promise.all([
axios.get('/api/users'),
axios.get('/api/posts'),
axios.get('/api/stats'),
]);
console.log('用户:', usersRes.data);
console.log('文章:', postsRes.data);
console.log('统计:', statsRes.data);
} catch (error) {
// 任意一个请求失败,Promise.all 都会进入 catch
console.error('加载失败:', error);
}
}
axios.all 和 axios.spread 也可用于并发请求,但它们只是 Promise.all 和数组解构的封装,上述写法更简洁直白。
要点:Promise.all 中任一请求失败都会导致整体进入 catch。如果希望部分失败时仍能获取成功的结果,可使用 Promise.allSettled()。