Axios学习目标
Axios与API交互 | 1、Axios配置与使用 |
2、请求/响应拦截器 | |
3、API设计模式(了解RESTful风格即可) |
学习参考:起步 | Axios中文文档 | Axios中文网
什么是Axios
Axios 是一个基于 Promise 的现代化 HTTP 客户端库,专门用于浏览器和 Node.js 环境。
其核心特性有如下:
-
跨平台支持:
- 在浏览器中通过 XMLHttpRequest 发送请求
- 在 Node.js 中通过 http 模块发送请求
-
Promise API:
- 所有请求都返回 Promise 对象
- 支持 async/await 语法
-
自动转换:
- 自动转换请求和响应数据(如 JSON 转换)
- 可自定义转换逻辑
-
拦截器系统:
- 请求和响应拦截
- 可用于添加认证头、处理错误等
-
取消请求:
- 支持取消正在进行的请求
- 使用 CancelToken 或 AbortController
经常使用于:
- 前端应用与 RESTful API 交互
- 需要统一处理 HTTP 请求的大型应用
- 需要请求拦截(如添加认证头)的应用
- 需要取消请求功能的复杂交互应用
- 同构应用(既在浏览器又在服务器运行)
配置与使用
安装
使用 npm:
npm install axios
使用cdn:
https://cdn.bootcdn.net/ajax/libs/axios/1.3.5/axios.min.js
<script crossorigin="anonymous" src="https://cdn.bootcdn.net/ajax/libs/axios/1.3.5/axios.min.js"></script>
示例:
服务器端:
const express = require('express');
//创建应用对象
const app = express();
// 添加请求体解析
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
//创建路由规则
// Axios请求
app.all('/axios-server', (req, res) => {
// 设置响应头
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Headers', '*');
// 设置响应体
const data ={name:'axios发送的请求'};
res.send(JSON.stringify(data));
//res.send('Its Axios Qusetion!');
});
// 404处理
app.use((req, res) => {
res.status(404).send('Not Found');
});
//监听端口启动服务
app.listen(8000, () => {
console.log('Server is running on port 8000');
});
html文件:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>axios 发送AJAX请求</title>
<link crossorigin="anonymous" href="https://cdn.bootcss.com/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
<script crossorigin="anonymous" src="https://cdn.bootcdn.net/ajax/libs/axios/1.3.5/axios.min.js"></script>
</head>
<body>
<div class="container">
<h2 class="page-header">Axios 发送AJAX请求</h2>
<button class="btn btn-primary">GET</button>
<button class="btn btn-danger">POST</button>
<button class="btn btn-info">通用型</button>
</div>
<script>
const btns = document.querySelectorAll("button");
// GET请求示例
btns[0].onclick = function() {
axios.get('http://127.0.0.1:8000/axios-server', {
params: {
a: 100,
b: 200
},
//请求头信息
headers:{
name:'value',
age:20
}
})
.then(function(response) {
console.log(response.data);
})
.catch(function(error) {
console.error('请求失败:', error);
});
};
// POST请求示例
btns[1].onclick = function() {
axios.post('http://127.0.0.1:8000/axios-server', {
username: 'admin',
password: '123456'
})
.then(function(response) {
console.log(response.data);
});
};
// 通用AJAX请求示例
btns[2].onclick = function() {
axios({
method: 'POST',
url: 'http://127.0.0.1:8000/axios-server',
data: {
key1: 'value1',
key2: 'value2'
}
})
.then(function(response) {
console.log(response.data);
});
};
</script>
</body>
</html>
可以直接浏览器打开代码查看一下F12控制台的信息,这里不做重点讲解,只了解使用。
请求/响应拦截器
请求拦截器
// 添加请求拦截器
axios.interceptors.request.use(
function (config) {
/**
* 在发送请求前做些什么
* config对象包含请求的所有配置信息
* 可以在这里统一处理以下内容:
* 1. 添加认证token
* 2. 添加公共参数
* 3. 显示loading状态
* 4. 记录请求日志
*/
// 添加认证token
const token = localStorage.getItem('authToken');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
// 添加时间戳防止缓存
if (config.method === 'get') {
config.params = config.params || {};
config.params._t = Date.now();
}
// 必须返回修改后的config
return config;
},
function (error) {
/**
* 对请求错误做些什么
* 通常是在请求配置出错时触发
* 比如config格式不正确等
*/
console.error('请求配置错误:', error);
// 返回一个被拒绝的Promise,会进入catch流程
return Promise.reject(error);
}
);
响应拦截器
// 添加响应拦截器
axios.interceptors.response.use(
function (response) {
/**
* 对响应数据做点什么
* 2xx范围内的状态码都会触发这个函数
* 可以在这里:
* 1. 统一处理响应数据格式
* 2. 隐藏loading状态
* 3. 处理业务特定的状态码
*/
// 直接返回response.data,简化后续处理
return response.data;
// 或者根据业务状态码进一步处理
if (response.data.code === 200) {
return response.data.data;
} else {
// 业务逻辑错误
return Promise.reject(response.data.message);
}
},
function (error) {
/**
* 对响应错误做点什么
* 超出2xx范围的状态码都会触发这个函数
* 可以在这里:
* 1. 统一处理错误
* 2. 根据状态码跳转页面
* 3. 显示错误提示
*/
// 错误对象结构说明
if (error.response) {
// 请求已发出,服务器返回了错误状态码
const { status, data } = error.response;
switch (status) {
case 401:
// 未授权,跳转到登录页
window.location.href = '/login';
break;
case 403:
// 禁止访问,显示权限不足提示
showToast('权限不足,请联系管理员');
break;
case 404:
// 资源不存在
showToast('请求的资源不存在');
break;
case 500:
// 服务器错误
showToast('服务器内部错误,请稍后再试');
break;
default:
// 其他错误
showToast(`请求错误: ${status}`);
}
// 可以在这里记录错误日志
logError(error);
} else if (error.request) {
// 请求已发出但没有收到响应
console.error('无响应:', error.request);
showToast('网络连接异常,请检查网络');
} else {
// 设置请求时发生了错误
console.error('请求配置错误:', error.message);
showToast('请求配置错误');
}
// 继续抛出错误,让调用者可以处理
return Promise.reject(error);
}
);
API设计模式与RESTful最佳实践
RESTful API设计原则详解
1. 资源导向设计:
- 使用名词而非动词表示资源(如
/users
而不是/getUsers
) - 资源使用复数形式(如
/articles
而不是/article
) - 层级关系表达:
/users/123/posts
表示用户123的所有帖子
2. HTTP方法语义:
方法 | 语义 | 幂等性 | 安全性 | 请求体 | 典型状态码 | 适用场景 |
---|---|---|---|---|---|---|
GET | 获取资源 | ✔️ 是 | ✔️ 是 | ❌ 无 | 200 OK 404 Not Found | 查询数据、获取资源详情 |
POST | 创建资源 | ❌ 否 | ❌ 否 | ✔️ 有 | 201 Created 400 Bad Request | 创建新资源、提交表单 |
PUT | 替换/完整更新资源 | ✔️ 是 | ❌ 否 | ✔️ 有 | 200 OK 204 No Content | 全量更新(需传完整字段) |
PATCH | 部分更新资源 | ❌ 否 | ❌ 否 | ✔️ 有 | 200 OK 422 Unprocessable Entity | 增量更新(只需传修改字段) |
DELETE | 删除资源 | ✔️ 是 | ❌ 否 | ❌ 无 | 204 No Content 404 Not Found | 删除指定资源 |
3. 状态码使用指南:
// 2xx 成功
200 OK - 常规成功响应
201 Created - 资源创建成功
204 No Content - 成功但无返回内容
// 4xx 客户端错误
400 Bad Request - 请求格式错误
401 Unauthorized - 需要认证
403 Forbidden - 无权限访问
404 Not Found - 资源不存在
// 5xx 服务器错误
500 Internal Server Error - 服务器内部错误
503 Service Unavailable - 服务不可用
完整API封装示例
// src/api/auth.js - 认证相关API
import axios from './axiosInstance';
export default {
/**
* 用户登录
* @param {Object} credentials - 登录凭据
* @param {string} credentials.username - 用户名
* @param {string} credentials.password - 密码
* @returns {Promise} 包含用户数据的Promise
*/
login(credentials) {
return axios.post('/auth/login', credentials)
.then(response => {
// 登录成功处理
const { token, user } = response.data;
// 存储token到本地存储
localStorage.setItem('authToken', token);
// 返回用户数据
return user;
});
},
/**
* 用户注销
* @returns {Promise} 空Promise
*/
logout() {
// 清除本地token
localStorage.removeItem('authToken');
// 调用服务器注销接口
return axios.post('/auth/logout');
},
/**
* 获取当前用户信息
* @returns {Promise} 包含用户信息的Promise
*/
getCurrentUser() {
return axios.get('/auth/me')
.then(response => response.data);
}
};
// src/api/users.js - 用户管理API
import axios from './axiosInstance';
export default {
/**
* 获取用户列表
* @param {Object} [params] - 查询参数
* @param {number} [params.page=1] - 页码
* @param {number} [params.limit=10] - 每页数量
* @returns {Promise} 包含用户列表和分页信息的Promise
*/
getUsers(params = { page: 1, limit: 10 }) {
return axios.get('/users', { params })
.then(response => ({
users: response.data.items,
pagination: response.data.pagination
}));
},
/**
* 创建新用户
* @param {Object} userData - 用户数据
* @returns {Promise} 包含新用户信息的Promise
*/
createUser(userData) {
return axios.post('/users', userData)
.then(response => response.data);
},
/**
* 更新用户信息
* @param {number} id - 用户ID
* @param {Object} updates - 更新字段
* @param {boolean} [partial=false] - 是否部分更新
* @returns {Promise} 包含更新后用户信息的Promise
*/
updateUser(id, updates, partial = false) {
const method = partial ? 'patch' : 'put';
return axios[method](`/users/${id}`, updates)
.then(response => response.data);
},
/**
* 删除用户
* @param {number} id - 用户ID
* @returns {Promise} 空Promise
*/
deleteUser(id) {
return axios.delete(`/users/${id}`);
}
};
在Vue组件中使用API的示例
// src/components/UserList.vue
import userAPI from '@/api/users';
import authAPI from '@/api/auth';
export default {
data() {
return {
users: [],
currentUser: null,
loading: false,
pagination: {
page: 1,
limit: 10,
total: 0
}
};
},
async created() {
// 组件创建时获取当前用户和用户列表
await this.fetchCurrentUser();
await this.fetchUsers();
},
methods: {
// 获取当前登录用户
async fetchCurrentUser() {
try {
this.currentUser = await authAPI.getCurrentUser();
} catch (error) {
console.error('获取用户信息失败:', error);
this.$router.push('/login');
}
},
// 获取用户列表
async fetchUsers() {
this.loading = true;
try {
const { users, pagination } = await userAPI.getUsers({
page: this.pagination.page,
limit: this.pagination.limit
});
this.users = users;
this.pagination = {
...this.pagination,
total: pagination.total
};
} catch (error) {
console.error('获取用户列表失败:', error);
this.$message.error('加载用户列表失败,请重试');
} finally {
this.loading = false;
}
},
// 删除用户
async handleDelete(userId) {
try {
await this.$confirm('确定要删除这个用户吗?', '提示', {
type: 'warning'
});
await userAPI.deleteUser(userId);
// 删除成功后刷新列表
this.fetchUsers();
this.$message.success('删除用户成功');
} catch (error) {
if (error !== 'cancel') {
console.error('删除用户失败:', error);
this.$message.error('删除用户失败');
}
}
},
// 切换页码
handlePageChange(page) {
this.pagination.page = page;
this.fetchUsers();
}
}
};
总结:Axios最佳实践
-
配置管理:
- 使用
axios.create()
创建不同用途的实例 - 将基础URL、超时时间等配置集中管理
- 使用
-
拦截器使用:
- 请求拦截器处理认证、公共参数
- 响应拦截器统一处理错误和返回数据
-
API封装:
- 按功能模块组织API
- 为每个方法添加清晰的JSDoc注释
- 统一返回Promise便于调用
-
错误处理:
- 区分网络错误、服务器错误和业务错误
- 在拦截器和具体调用处分层处理
-
RESTful设计:
- 遵循资源导向原则
- 正确使用HTTP方法和状态码
- 保持接口风格一致