Vue.js 接口封装最佳实践:从基础到高级

发布时间:2026/8/9 3:44:26
Vue.js 接口封装最佳实践:从基础到高级 1. 为什么需要封装 Vue 接口在 Vue.js 项目中直接在每个组件中调用axios.get()或fetch()会导致以下问题代码重复相同的 API 基础 URL、请求头配置在每个请求中重复编写。难以维护当后端接口地址变更或需要统一添加认证逻辑时需要修改所有相关组件。错误处理分散每个组件都需要单独处理网络错误、超时、权限验证等。缺乏统一拦截器无法全局处理请求/响应如添加 loading 状态、统一错误提示。因此对 HTTP 请求进行统一封装是 Vue 项目架构中必不可少的一环。2. 基础封装创建统一的请求实例首先我们使用 Axios最流行的 HTTP 客户端创建一个基础请求实例。// src/utils/request.js import axios from axios; // 创建 axios 实例 const request axios.create({ baseURL: process.env.VUE_APP_API_BASE_URL || /api, // 基础 URL timeout: 10000, // 请求超时时间 headers: { Content-Type: application/json;charsetUTF-8 } }); // 请求拦截器 request.interceptors.request.use( config { // 在发送请求之前做些什么例如添加 token const token localStorage.getItem(token); if (token) { config.headers.Authorization Bearer ${token}; } return config; }, error { // 对请求错误做些什么 return Promise.reject(error); } ); // 响应拦截器 request.interceptors.response.use( response { // 对响应数据做点什么 const res response.data; // 假设后端返回格式为 { code: 200, data: {}, message: success } if (res.code 200) { return res.data; } else { // 业务错误处理 return Promise.reject(new Error(res.message || 请求失败)); } }, error { // 对响应错误做点什么 if (error.response) { // 服务器返回了错误状态码 switch (error.response.status) { case 401: // 未授权跳转到登录页 router.push(/login); break; case 403: // 权限不足 Message.error(权限不足请联系管理员); break; case 404: // 接口不存在 Message.error(请求的资源不存在); break; case 500: // 服务器内部错误 Message.error(服务器内部错误请稍后重试); break; default: Message.error(error.response.data.message || 请求失败); } } else if (error.request) { // 请求发送了但没有收到响应 Message.error(网络异常请检查网络连接); } else { // 请求配置出错 Message.error(请求配置错误); } return Promise.reject(error); } ); export default request;3. 进阶封装按模块组织 API将不同业务模块的 API 集中管理提高代码可读性和维护性。// src/api/user.js import request from /utils/request; // 用户相关接口 export const userApi { // 获取用户列表 getUsers(params) { return request({ url: /users, method: get, params }); }, // 获取用户详情 getUserById(id) { return request({ url: /users/${id}, method: get }); }, // 创建用户 createUser(data) { return request({ url: /users, method: post, data }); }, // 更新用户 updateUser(id, data) { return request({ url: /users/${id}, method: put, data }); }, // 删除用户 deleteUser(id) { return request({ url: /users/${id}, method: delete }); } }; // src/api/product.js import request from /utils/request; // 商品相关接口 export const productApi { // 获取商品列表 getProducts(params) { return request({ url: /products, method: get, params }); }, // 获取商品详情 getProductById(id) { return request({ url: /products/${id}, method: get }); } };4. 在 Vue 组件中使用封装好的 API在 Vue 组件中我们可以优雅地调用封装好的 API。template div h1用户列表/h1 ul li v-foruser in users :keyuser.id {{ user.name }} - {{ user.email }} /li /ul button clickloadUsers加载用户/button /div /template script import { userApi } from /api/user; export default { name: UserList, data() { return { users: [] }; }, methods: { async loadUsers() { try { // 调用封装好的 API this.users await userApi.getUsers({ page: 1, pageSize: 10 }); } catch (error) { console.error(加载用户失败:, error); } } }, mounted() { this.loadUsers(); } }; /script5. 高级技巧使用 TypeScript 增强类型安全在 TypeScript 项目中我们可以为 API 添加类型定义获得更好的开发体验。// src/types/api.ts // 用户相关类型 export interface User { id: number; name: string; email: string; role: string; } export interface UserListParams { page?: number; pageSize?: number; keyword?: string; } export interface UserListResponse { list: User[]; total: number; } // src/api/user.ts import request from /utils/request; import type { User, UserListParams, UserListResponse } from /types/api; export const userApi { // 获取用户列表带类型 getUsers(params?: UserListParams): PromiseUserListResponse { return request({ url: /users, method: get, params }); }, // 获取用户详情带类型 getUserById(id: number): PromiseUser { return request({ url: /users/${id}, method: get }); }, // 创建用户带类型 createUser(data: OmitUser, id): PromiseUser { return request({ url: /users, method: post, data }); } };6. 最佳实践总结统一配置创建统一的请求实例配置 baseURL、超时时间、请求头等。拦截器管理使用请求/响应拦截器统一处理 token、loading、错误提示等。模块化组织按业务模块组织 API提高代码可维护性。错误处理在拦截器中统一处理 HTTP 错误和业务错误。类型安全在 TypeScript 项目中为 API 添加类型定义。环境配置使用环境变量管理不同环境的 API 地址。取消请求对于频繁触发的请求如搜索使用 CancelToken 取消之前的请求。7. 常见问题与解决方案7.1 如何处理重复请求使用 Axios 的 CancelToken 或 AbortController 取消重复请求。// 使用 CancelToken let cancelTokenSource null; export const searchApi { search(keyword) { // 取消之前的请求 if (cancelTokenSource) { cancelTokenSource.cancel(取消重复请求); } // 创建新的 CancelToken cancelTokenSource axios.CancelToken.source(); return request({ url: /search, method: get, params: { keyword }, cancelToken: cancelTokenSource.token }); } };7.2 如何添加请求重试机制可以在响应拦截器中实现重试逻辑。// 响应拦截器中添加重试逻辑 request.interceptors.response.use( response { return response; }, async error { const config error.config; // 设置重试次数 config.__retryCount config.__retryCount || 0; // 检查是否达到最大重试次数 if (config.__retryCount 3) { return Promise.reject(error); } // 增加重试计数 config.__retryCount 1; // 创建新的 promise 来处理指数退避 const backoff new Promise(resolve { setTimeout(() { resolve(); }, 1000 * config.__retryCount); }); // 等待退避时间后重试请求 await backoff; return request(config); } );