Vue3项目中Axios的完整封装方案与实现

2026-07-24 19:47:10 30 次阅读

Vue.js 组合现代前端工程化开发时,接口请求层的设计往往决定了项目的可维护性与扩展能力。很多团队在项目初期直接使用 Axios 发起请求,随着业务增长逐渐暴露出配置分散、重复代码多、错误处理不统一、Token管理混乱等问题。对Axios进行系统化封装,是Vue3项目走向工程化的重要一步。


一、Axios封装的核心目标

接口层封装不是简单“包一层请求方法”,而是建立一套可复用、可扩展、可维护的请求体系。Vue3项目中通常需要解决以下问题:

请求基础配置统一管理,包括baseURL、timeout、headers等
请求与响应拦截统一处理,如Token注入与错误拦截
业务接口解耦,避免页面直接依赖Axios实例
支持多环境切换(开发、测试、生产)
支持请求取消、重复请求控制、loading状态管理
兼容TypeScript类型提示


二、创建Axios实例(核心基础)

建议在src/utils/request.ts中统一管理实例。

TypeScript
import axios from "axios";

const service = axios.create({
baseURL: import.meta.env.VITE_BASE_API,
timeout: 15000,
withCredentials: false,
});

export default service;

通过环境变量控制接口地址,可以避免硬编码带来的维护成本。


三、请求拦截器:统一注入Token与参数处理

请求拦截器是封装的核心环节之一,常用于处理认证信息与公共参数。

TypeScript
service.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三部分,通过拦截器可以统一处理。

TypeScript
service.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)

为了进一步降低使用成本,可以对常用请求方法进行二次封装。

TypeScript
import 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 });
};

这样业务层调用会更加清晰:

TypeScript
import { 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中注册:

TypeScript
import requestPlugin from "@/plugins/request";

app.use(requestPlugin);

组件中即可直接使用:

TypeScript
this.$http.get("/user/list");

八、进阶能力:请求取消与防抖控制

在搜索或高频请求场景中,请求取消非常重要。

TypeScript
import axios from "axios";

const controller = new AbortController();

service.get("/search", {
signal: controller.signal,
});

// 取消请求
controller.abort();

对于输入框联想搜索,可以结合防抖函数提升体验。


九、Loading统一管理方案

可以通过请求拦截器结合状态管理实现全局loading。

TypeScript
let 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类型增强(提升工程质量)

定义统一响应结构:

TypeScript
export interface ApiResponse<T> {
code: number;
message: string;
data: T;
}

在请求中使用泛型:

TypeScript
export const getUserList = (): Promise<User[]> => {
return get("/user/list");
};

类型约束可以显著减少运行时错误。


十一、常见优化点总结

合理设置baseURL与环境变量
避免在组件中直接使用Axios
统一错误处理逻辑
控制Token刷新机制
合理拆分API模块
结合TypeScript增强安全性
控制请求并发与重复调用


经过完整封装后,Vue3项目中的接口层会从“零散调用”升级为“可控的服务层结构”,不仅提升开发效率,也让后期维护成本显著降低。