三十的博客

Axios 简单网络请求封装

发布时间
阅读量 加载中...

背景

最近一直在学习前端 Vue3 开发, 已经初步掌握了一些基本的用法。今天偶然发现了前端同事仓库代码里面封装的 axios 请求,和我所常见的版本不一样。仔细阅读了下,大致原理都是差不多的,但是看来更优雅了些。记录下两个版本,也方便后期查看学习或者在新项目中复制使用。

普通版本

我所常见的普遍版本也是我一直在使用的版本。

封装

ts
// src/utils/request.ts

import axios from "axios";
import { ElMessage } from "element-plus";

let request = axios.create({
  baseURL: "/api",
  timeout: 5000,
});

request.interceptors.request.use((config) => {
  return config;
});

request.interceptors.response.use(
  (response) => {
    return response.data;
  },
  (error) => {
    let message = "";
    let status = error.response.status;

    switch (status) {
      case 404:
        message = "请求地址不存在";
        break;
      case 500:
        message = "服务器繁忙";
        break;
      case 401:
        message = "Token 过期";
        break;
      case 403:
        message = "没有权限访问";
        break;
    }

    ElMessage({
      type: "error",
      message,
    });

    return Promise.reject(error);
  }
);

export default request;

调用方式

ts
// src/api/user/index.ts

import request from "@/utils/request";
import type {
  LoginForm,
  LoginResponseData,
  UserInfoResponseData,
} from "./types";

const API = {
  Login: "/user/login",
  UserInfo: "/user/info",
};

// 登录接口
export const reqLogin = (data: LoginForm) =>
  request.post<any, LoginResponseData>(API.Login, data);

// 获取用户信息
export const reqUserInfo = () =>
  request.get<any, UserInfoResponseData>(API.UserInfo);

优雅的版本

封装

ts
// src/types/request.type.ts

export type TResult<T> = {
  code: number;
  msg: string;
  data?: T;
  count: number;
};

export enum EResponseCode {
  SUCCESS = 200,
}
ts
// src/api/index.ts

import axios, {
  AxiosError,
  type AxiosInstance,
  type AxiosRequestConfig,
  type AxiosResponse,
} from "axios";
import { ElNotification } from "element-plus";
import { type TResult, EResponseCode } from "@/types/request.type";

const URL: string = "/";

const config = {
  // 默认地址
  baseURL: URL,
  // 设置超时时间
  timeout: 30000,
  // 跨域时候允许携带凭证
  withCredentials: true,
};

class RequestHttp {
  service: AxiosInstance;
  public constructor(config: AxiosRequestConfig) {
    // 实例化axios
    this.service = axios.create(config);

    /**
     * 请求拦截器
     * 客户端发送请求 -> [请求拦截器] -> 服务器
     * token校验(JWT) : 接受服务器返回的token,存储到vuex/pinia/本地储存当中
     */
    this.service.interceptors.request.use(
      (config) => {
        return {
          ...config,
        };
      },
      (error: AxiosError) => {
        // 请求报错
        Promise.reject(error);
      }
    );

    /**
     * 响应拦截器
     * 服务器换返回信息 -> [拦截统一处理] -> 客户端JS获取到信息
     */
    this.service.interceptors.response.use(
      (response: AxiosResponse) => {
        const { data } = response; // 解构
        if (data.code == EResponseCode.SUCCESS) {
          return Promise.resolve(data);
        } else {
          ElNotification.warning(data.msg);
          return Promise.reject(data);
        }
      },
      (error: AxiosError) => {
        ElNotification.error(error.message);
      }
    );
  }

  // 常用方法封装
  get<T>(url: string, params?: object): Promise<TResult<T>> {
    return this.service.get(url, { params });
  }
  post<T>(url: string, params?: object): Promise<TResult<T>> {
    return this.service.post(url, params);
  }
  put<T>(url: string, params?: object): Promise<TResult<T>> {
    return this.service.put(url, params);
  }
  delete<T>(url: string, params?: object): Promise<TResult<T>> {
    return this.service.delete(url, { params });
  }
}

// 导出一个实例对象
export default new RequestHttp(config);

调用方式

ts
// src/api/modules/system.api.ts

import RequestHttp from "../index";
import type { Router } from "@/types/global.type";

export namespace SystemApi {
  export const getMenu = () => {
    return RequestHttp.get<Router.TApiMenuItem[]>("/system/getMenu");
  };
}
#Http请求封装 #Axios #Typescript #Http