前端API请求封装
- 如何封装HTTP请求库
- 理解axios拦截器的作用
- 掌握Token认证机制
- 学会API接口的标准化管理
- 了解前后端分离架构的通信方式
第一部分:HTTP请求封装 (request.js)
1. 导入依赖模块
import axios from "axios";
import { ElMessage } from "element-plus";
import store from "@/store";
import router from "@/router";
详细解释:
- axios: 最流行的HTTP请求库,用于发送AJAX请求
- ElMessage: Element Plus UI框架的消息提示组件,用于显示成功/错误信息
- store: Vuex状态管理器,存储全局数据(如用户token)
- router: Vue Router路由管理器,用于页面跳转
初学者要点:
@/
是webpack的别名,通常指向src/
目录- 这些都是Vue.js生态系统中的常用库
2. 创建axios实例
const service = axios.create({baseURL: "/api", // 后端API基础地址timeout: 5000, // 请求超时时间5秒
});
为什么要创建实例?
- 可以设置统一的配置(如基础URL、超时时间)
- 可以添加拦截器进行统一处理
- 避免每次请求都要重复配置
配置说明:
- baseURL: 所有请求的基础路径,比如请求
/users
实际会变成/api/users
- timeout: 超过5秒没响应就取消请求,防止页面卡死
3. 请求拦截器 - 自动添加认证
service.interceptors.request.use((config) => {// 如果有token,添加到请求头if (store.getters.token) {config.headers["Authorization"] = "Bearer " + store.getters.token;}console.log(store.getters.token);return config;},(error) => {console.log(error);return Promise.reject(error);}
);
什么是拦截器?
拦截器就像"检查站",每个请求发送前都会经过这里进行处理。
这段代码做了什么?
- 检查token: 从Vuex store中获取用户的登录凭证
- 添加认证头: 如果有token,就在HTTP头部加上
Authorization: Bearer xxxxx
- Bearer Token: 这是一种标准的认证方式,后端会验证这个token
为什么要这样做?
- 避免每个API调用都手动添加token
- 统一管理认证逻辑
- 提高代码复用性
4. 响应拦截器 - 统一处理响应
service.interceptors.response.use((response) => {// 处理文件下载响应if (response.config.responseType === 'blob') {return response.data;}// 处理CSV文件响应const contentType = response.headers['content-type'];if (contentType && contentType.includes('text/csv')) {return response.data;}const res = response.data;console.log(res);// 检查业务状态码if (res.code !== 200) {// 显示错误消息ElMessage({message: res.message || "请求失败",type: "error",duration: 5 * 1000,});// 处理未登录状态if (res.code === 401) {store.dispatch("user/logout");router.push("/login");}return Promise.reject(new Error(res.message || "请求失败"));} else {return res; // 成功时返回数据}},(error) => {// 处理网络错误console.log("err" + error);ElMessage({message: error.message,type: "error",duration: 5 * 1000,});return Promise.reject(error);}
);
响应拦截器的作用:
-
特殊文件处理:
- blob类型用于文件下载
- CSV文件直接返回原始数据
-
统一错误处理:
- 自动显示错误提示
- 处理401未登录状态(自动跳转登录页)
- 减少重复的错误处理代码
-
数据格式统一:
- 成功时返回
res.data
- 失败时抛出错误
- 成功时返回
HTTP状态码 vs 业务状态码:
- HTTP状态码: 200表示请求成功到达服务器
- 业务状态码: res.code表示业务操作是否成功
第二部分:API接口层 (user.js)
1. 导入请求模块
import request from "@/utils/request";
这里导入我们刚才封装的请求工具。
2. 认证相关接口
登录接口
export function login(data) {return request({url: "/auth/login",method: "post",data,});
}
使用示例:
// 在组件中使用
import { login } from '@/api/user';const loginForm = {username: 'admin',password: '123456'
};login(loginForm).then(response => {console.log('登录成功', response);
}).catch(error => {console.log('登录失败', error);
});
登出接口
export function logout() {return request({url: "/auth/logout",method: "post",});
}
3. 用户管理接口(CRUD操作)
获取用户列表(分页)
export function getUserList(params) {return request({url: "/users/page",method: "get",params,});
}
参数说明:
- params: 查询参数对象,如
{pageNum: 1, pageSize: 10, username: 'admin'}
- method: “get”: GET请求,参数会拼接到URL后面
使用示例:
getUserList({pageNum: 1,pageSize: 10,username: 'zhang'
}).then(response => {console.log('用户列表:', response.data);
});
获取所有用户(不分页)
export function getAllUsers() {return request({url: "/users",method: "get",});
}
获取单个用户
export function getUser(id) {return request({url: `/users/${id}`, // RESTful风格URLmethod: "get",});
}
RESTful API设计:
- GET
/users/{id}
- 获取指定用户 - POST
/users
- 创建用户 - PUT
/users/{id}
- 更新用户 - DELETE
/users/{id}
- 删除用户
创建用户
export function createUser(data) {return request({url: "/users",method: "post",data,});
}
使用示例:
const newUser = {username: 'newuser',password: '123456',email: 'newuser@example.com'
};createUser(newUser).then(response => {console.log('用户创建成功');
});
更新用户
export function updateUser(id, data) {return request({url: `/users/${id}`,method: "put",data,});
}
删除用户
export function deleteUser(id) {return request({url: `/users/${id}`,method: "delete",});
}
4. 文件操作接口
导出CSV文件
export function exportUsersCsv() {return request({url: "/csv/export",method: "get",responseType: "blob", // 关键:指定响应类型为二进制});
}
重要说明:
- responseType: “blob”: 告诉axios这是一个文件下载请求
- blob是浏览器处理文件的数据类型
使用示例:
exportUsersCsv().then(blob => {// 创建下载链接const url = window.URL.createObjectURL(blob);const link = document.createElement('a');link.href = url;link.download = 'users.csv';link.click();
});
导入CSV文件
export function importUsersCsv(formData) {return request({url: "/csv/import",method: "post",data: formData,headers: {"Content-Type": "multipart/form-data", // 文件上传必需},});
}
文件上传说明:
- 使用FormData对象包装文件
- 设置Content-Type为multipart/form-data
使用示例:
// 在文件选择事件中
const handleFileUpload = (file) => {const formData = new FormData();formData.append('file', file);importUsersCsv(formData).then(response => {console.log('文件上传成功');});
};
修改密码
export function changePassword(id, data) {return request({url: `/users/${id}/password`,method: "put",data,});
}
-最佳实践和学习要点
1. 代码组织结构
src/
├── utils/
│ └── request.js # HTTP请求封装
├── api/
│ ├── user.js # 用户相关API
│ ├── product.js # 产品相关API
│ └── order.js # 订单相关API
└── store/└── index.js # Vuex状态管理
2. 错误处理策略
- 网络层错误: 在拦截器中统一处理
- 业务层错误: 根据错误码进行不同处理
- 用户友好: 显示易懂的错误信息
3. 安全性考虑
- Token管理: 自动添加到请求头
- 请求超时: 防止长时间等待
- 自动登出: token过期时自动跳转
4. 性能优化
- 请求复用: 相同的API不重复定义
- 拦截器: 减少重复代码
- 错误处理: 统一处理,减少冗余
5. 调试技巧
- 使用
console.log
打印请求和响应 - 浏览器开发者工具查看网络请求
- 检查请求头中的token是否正确
🔍 常见问题和解决方案
Q1: 为什么要用 /api
作为baseURL?
A: 在生产环境中,通常通过nginx等反向代理将 /api
路径转发到后端服务器,这样可以避免跨域问题。
Q2: Bearer Token是什么?
A: Bearer Token是OAuth 2.0标准中的一种认证方式,格式为 Authorization: Bearer <token>
,后端通过验证token来确认用户身份。
Q3: 为什么要分离请求封装和API接口?
A:
- request.js: 负责通用的HTTP配置和拦截器
- user.js: 负责具体的业务接口定义
- 这样分层使代码更清晰,维护更容易
Q4: 如何处理文件上传进度?
A: 可以在axios配置中添加 onUploadProgress
回调:
return request({url: "/csv/import",method: "post",data: formData,onUploadProgress: (progressEvent) => {const progress = Math.round((progressEvent.loaded * 100) / progressEvent.total);console.log(`上传进度: ${progress}%`);}
});
- 学习Promise和async/await: 更好地处理异步操作
- 了解HTTP协议: 理解状态码、请求方法的含义
- 掌握RESTful API设计: 标准的API设计规范
- 学习Vuex: 深入理解状态管理
- 了解TypeScript: 为API接口添加类型定义