如何打造优雅、高效的前端axios请求

168 阅读3分钟

前言

 前言

在当今数字化时代,前端开发扮演着至关重要的角色。用户对网页应用的体验要求越来越高,这不仅体现在界面设计上,更体现在应用的性能和响应速度上。网络请求作为前端与后端交互的核心环节,其质量和效率直接影响到用户的使用体验。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: stringparams?: 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 环境下,结合了类型检查,增强了代码的健壮性。
  • • 区分了接口地址和接口请求方法,使代码结构更加清晰,便于团队协作和后续扩展。