Vue.js 组合现代前端工程化开发时,接口请求层的设计往往决定了项目的可维护性与扩展能力。很多团队在项目初期直接使用 Axios 发起请求,随着业务增长逐渐暴露出配置分散、重复代码多、错误处理不统一、Token管理混乱等问题。对Axios进行系统化封装,是Vue3项目走向工程化的重要一步。
一、Axios封装的核心目标
接口层封装不是简单“包一层请求方法”,而是建立一套可复用、可扩展、可维护的请求体系。Vue3项目中通常需要解决以下问题:
请求基础配置统一管理,包括baseURL、timeout、headers等
请求与响应拦截统一处理,如Token注入与错误拦截
业务接口解耦,避免页面直接依赖Axios实例
支持多环境切换(开发、测试、生产)
支持请求取消、重复请求控制、loading状态管理
兼容TypeScript类型提示
二、创建Axios实例(核心基础)
建议在src/utils/request.ts中统一管理实例。
TypeScriptimport axios from "axios";
const service = axios.create({
baseURL: import.meta.env.VITE_BASE_API,
timeout: 15000,
withCredentials: false,
});
export default service;
通过环境变量控制接口地址,可以避免硬编码带来的维护成本。
三、请求拦截器:统一注入Token与参数处理
请求拦截器是封装的核心环节之一,常用于处理认证信息与公共参数。
TypeScriptservice.interceptors.request.use(
(config) => {
const token = localStorage.getItem("token");
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
(error) => {
return Promise.reject(error);
}
);
如果项目涉及签名或时间戳,也可以在这里统一处理,避免散落在业务代码中。
四、响应拦截器:统一错误处理与数据解构
后端返回结构通常包含code、message、data三部分,通过拦截器可以统一处理。
TypeScriptservice.interceptors.response.use(
(response) => {
const res = response.data;
if (res.code !== 200) {
console.error(res.message || "Error");
return Promise.reject(res);
}
return res.data;
},
(error) => {
let message = "网络异常";
if (error.response?.status === 401) {
message = "登录已过期";
}
console.error(message);
return Promise.reject(error);
}
);
统一处理后,页面层无需重复判断code字段,提高代码可读性。
五、封装请求方法(get/post/put/delete)
为了进一步降低使用成本,可以对常用请求方法进行二次封装。
TypeScriptimport service from "./request";
export const get = (url: string, params?: any) => {
return service.get(url, { params });
};
export const post = (url: string, data?: any) => {
return service.post(url, data);
};
export const put = (url: string, data?: any) => {
return service.put(url, data);
};
export const del = (url: string, data?: any) => {
return service.delete(url, { data });
};
这样业务层调用会更加清晰:
TypeScriptimport { get } from "@/utils/http";
get("/user/list");
六、API模块化管理(推荐结构)
建议按业务模块拆分接口文件,而不是集中在一个http文件中。
TypeScript// api/user.ts
import { get, post } from "@/utils/http";
export const getUserList = (params?: any) => {
return get("/user/list", params);
};
export const login = (data: any) => {
return post("/user/login", data);
};
这种方式的优势在于:
接口与业务强绑定
便于维护与重构
避免URL散落在页面组件中
七、在Vue3中统一注入(插件化封装)
可以将请求层封装为插件,提升全局可用性。
TypeScript// plugins/request.ts
import * as http from "@/utils/http";
export default {
install(app: any) {
app.config.globalProperties.$http = http;
},
};
在main.ts中注册:
TypeScriptimport requestPlugin from "@/plugins/request";
app.use(requestPlugin);
组件中即可直接使用:
TypeScriptthis.$http.get("/user/list");
八、进阶能力:请求取消与防抖控制
在搜索或高频请求场景中,请求取消非常重要。
TypeScriptimport axios from "axios";
const controller = new AbortController();
service.get("/search", {
signal: controller.signal,
});
// 取消请求
controller.abort();
对于输入框联想搜索,可以结合防抖函数提升体验。
九、Loading统一管理方案
可以通过请求拦截器结合状态管理实现全局loading。
TypeScriptlet requestCount = 0;
service.interceptors.request.use((config) => {
requestCount++;
// show loading
return config;
});
service.interceptors.response.use(
(res) => {
requestCount--;
// hide loading when requestCount === 0
return res;
},
(err) => {
requestCount--;
return Promise.reject(err);
}
);
这种方式避免每个接口手动控制loading状态。
十、TypeScript类型增强(提升工程质量)
定义统一响应结构:
TypeScriptexport interface ApiResponse<T> {
code: number;
message: string;
data: T;
}
在请求中使用泛型:
TypeScriptexport const getUserList = (): Promise<User[]> => {
return get("/user/list");
};
类型约束可以显著减少运行时错误。
十一、常见优化点总结
合理设置baseURL与环境变量
避免在组件中直接使用Axios
统一错误处理逻辑
控制Token刷新机制
合理拆分API模块
结合TypeScript增强安全性
控制请求并发与重复调用
经过完整封装后,Vue3项目中的接口层会从“零散调用”升级为“可控的服务层结构”,不仅提升开发效率,也让后期维护成本显著降低。