前言
前言
在当今数字化时代,前端开发扮演着至关重要的角色。用户对网页应用的体验要求越来越高,这不仅体现在界面设计上,更体现在应用的性能和响应速度上。网络请求作为前端与后端交互的核心环节,其质量和效率直接影响到用户的使用体验。Axios 作为一款优秀的HTTP库,在前端开发中被广泛应用。然而,如何在 Vue3 + TypeScript 环境下,将 Axios 封装得更加优雅、高效、可维护,是每个前端开发者都需要面对的问题。
本文将深入探讨如何在 Vue3 + TypeScript 环境下,打造优雅、高效的 Axios 请求。我们将从实际开发中的痛点出发,分析传统 Axios 使用方式的不足之处,并提出一系列优化方案。通过合理的封装,我们不仅可以提高代码的可读性和可维护性,还能显著提升应用的性能和用户体验。
1. 包安装
-
• 在项目中安装
axios:npm install axios
2. 创建 Axios 实例
在项目 src 目录下创建 api 文件夹,并在其中创建 axios.ts 文件:
import axios, { AxiosRequestConfig, AxiosResponse, AxiosInstance, AxiosPromise } from 'axios';
import { ElNotification } from 'element-plus';
// 创建 Axios 实例
const instance: AxiosInstance = axios.create({
baseURL: import.meta.env.VITE_APP_BASE_API, // 基础路径
timeout: 10000, // 超时时间
});
// 请求拦截器
instance.interceptors.request.use(
(config: AxiosRequestConfig) => {
// 请求拦截逻辑,如根据 env 设置不同环境的 token 等
return config;
},
(error) => Promise.reject(error)
);
// 响应拦截器
instance.interceptors.response.use(
(response: AxiosResponse) => {
// 成功时处理逻辑
const { code, data, msg } = response.data;
if (code === 200) {
return Promise.resolve(data);
} else if (code === 401) {
ElNotification({ type: 'error', message: '登录过期,请重新登录' });
return Promise.reject(msg);
} else {
ElNotification({ type: 'error', message: msg });
return Promise.reject(msg);
}
},
(error: AxiosError) => {
// 错误时处理逻辑
let msg = '';
const status = error.response?.status;
switch (status) {
case 401:
msg = '登录过期,请重新登录';
break;
case 403:
msg = '拒绝访问';
break;
case 404:
msg = `请求地址出错: ${error.response?.config?.url}`;
break;
case 500:
msg = '服务器内部错误';
break;
case 502:
msg = '网关错误';
break;
case 503:
msg = '服务不可用';
break;
case 504:
msg = '网关超时';
break;
default:
msg = error.message;
}
ElNotification({ type: 'error', message: msg });
return Promise.reject(error);
}
);
// 请求方法
instance.all = axios.all;
instance.spread = axios.spread;
instance.Axios = axios.Axios;
export default instance;
3. 接口地址封装
在 src/api 目录下创建 api.ts 文件,对接口地址进行封装:
// 示例接口配置
const api = {
users: {
get: () => `/api/v1/users`,
post: () => `/api/v1/user`,
put: (id: string) => `/api/v1/user/${id}`,
delete: (id: string) => `/api/v1/user/${id}`,
getDetail: (id: string) => `/api/v1/user/${id}`,
},
};
export default api;
4. 封装请求方法
在 src/api 下创建 apiInterceptor.ts 文件,封装请求和响应处理:
import instance from './axios';
import api from './api';
interface AxiosRequestFn<T> {
(options?: any): AxiosPromise<T>;
}
export const get = <T>(url: string, params?: any): AxiosPromise<T> => {
return instance.get<T>(url, { params });
};
export const post = <T>(url: string, data?: any): AxiosPromise<T> => {
return instance.post<T>(url, data);
};
export const put = <T>(url: string, data?: any): AxiosPromise<T> => {
return instance.put<T>(url, data);
};
export const del = <T>(url: string, data?: any): AxiosPromise<T> => {
return instance.delete<T>(url, { data });
};
export function getUsers<T>(page = 1, pageSize = 10): AxiosPromise<T> {
return get<T>(api.users.get(), { page, pageSize });
}
export function addUser<T>(data: any): AxiosPromise<T> {
return post<T>(api.users.post(), data);
}
export function getUserDetail<T>(id: string): AxiosPromise<T> {
return get<T>(api.users.getDetail(id));
}
export function updateUser<T>(id: string, data: any): AxiosPromise<T> {
return put<T>(api.users.put(id), data);
}
export function deleteUser<T>(id: string, data?: any): AxiosPromise<T> {
return del<T>(api.users.delete(id), data);
}
5. 在组件中使用
在 Vue 组件中调用封装后的请求方法:
<template>
<div>
<el-table :data="tableData" stripe style="width: 100%">
<el-table-column prop="name" label="姓名" width="180" />
<el-table-column prop="address" label="地址" />
</el-table>
</div>
</template>
<script setup lang="ts">
import { getUsers } from '@/api/apiInterceptor';
const tableData = ref([]);
// 获取用户列表
const getUserList = async () => {
try {
const res = await getUsers();
tableData.value = res;
} catch (err) {
console.error('获取用户列表失败:', err);
}
};
onMounted(() => {
getUserList();
});
</script>
总结
通过以上的封装,我们实现了以下几点:
- • 避免了硬编码接口地址,方便维护和管理。
- • 减少了重复的请求和响应处理逻辑,让代码更加简洁和复用。
- • 通过拦截器统一了请求和响应的处理,提高了代码的可读性和可靠性。
- • 在 Vue3 + TypeScript 环境下,结合了类型检查,增强了代码的健壮性。
- • 区分了接口地址和接口请求方法,使代码结构更加清晰,便于团队协作和后续扩展。