index.ts 用来暴露实例

import EnclosureHttp from "@/utils/http/requset";
const http = new EnclosureHttp();
export default http;

 request.ts 实现 axios 创建实例 请求拦截 响应拦截 和默认 的get post 封装(偷懒了,没有封装自定义的 get post put delete )

import Axios, {
  AxiosRequestConfig,
  AxiosResponse,
  AxiosError,
  AxiosInstance,
} from "axios";
import { Request } from "@/utils/http/types";

import { ElMessage } from "element-plus";
/**
 * 封装的 element-plus 的消息提示框
 * @param msg
 * @param type
 */
const message = (msg: string, type?: string) => {
  ElMessage({
    message: msg,
    type: type || "warning",
    duration: 1500,
  });
};

/**
 * 默认 create Axios 的配置参数
 */
const defaultConfig: AxiosRequestConfig = {
  baseURL: "",
  timeout: 10000, //10秒超时
  withCredentials: true,
  responseType: "json",
  transformRequest: [
    (data) => {
      //对请求的参数进行处理
      data = JSON.stringify(data);
      return data;
    },
  ],
  validateStatus() {
    // 使用async-await,处理reject情况较为繁琐,所以全部返回resolve,在业务代码中处理异常
    return true;
  },
  transformResponse: [
    (data) => {
      //对响应的数据进行处理
      if (typeof data === "string" && data.startsWith("{")) {
        data = JSON.parse(data);
      }
      return data;
    },
  ],
  headers: {
    Accept: "application/json, text/plain, */*",
    "Content-Type": "application/json",
    "X-Requested-With": "XMLHttpRequest",
  },
};
/**
 * Axios create的时候后去的配置参数
 * @param config
 */
const getConfig = (config?: AxiosRequestConfig): AxiosRequestConfig => {
  if (!config) return defaultConfig;
  return defaultConfig;
};

/**
 * 自定义封装的Axios 类
 */
class EnclosureHttp {
  constructor() {
    this.httpInterceptorsRequest();
    this.httpInterceptorsResponse();
  }

  /**
   * Axios 实例
   * @private
   */
  private static axiosInstance: AxiosInstance = Axios.create(getConfig());

  /**
   * 请求拦截
   * @private
   */
  private httpInterceptorsRequest(): void {
    EnclosureHttp.axiosInstance.interceptors.request.use(
      (config: AxiosRequestConfig) => {
        /*
         * 在请求发出去之前作出一下处理
         * */
        // console.log("config=>:", config);
        return config;
      },
      (err) => {
        return Promise.resolve(err);
      }
    );
  }

  /**
   * 响应拦截
   * @private
   */
  private httpInterceptorsResponse(): void {
    EnclosureHttp.axiosInstance.interceptors.response.use(
      (response: AxiosResponse) => {
        /*
         *   对响应的数据作出一些处理
         * */
        const { status } = response;
        let msg = "";
        if (status < 200 || status >= 300) {
          // 处理http错误,抛到业务代码
          if (typeof response.data === "string") {
            msg = "打盹了!!!";
            response.data = { msg };
          } else {
            response.data.msg = msg;
          }
        }
        return response;
      },
      (error: AxiosError) => {
        //请求出错的验证
        const { response } = error;
        if (response) {
          // 请求已发出,但是不在2xx的范围
          this.errorHandle(response.status, response.data.message);
          return Promise.reject(response);
        } else {
          // 处理断网的情况
          // eg:请求超时或断网时,更新state的network状态
          // network状态在app.vue中控制着一个全局的断网提示组件的显示隐藏
          // 后续增加断网情况下做的一些操作
          return Promise.reject(error);
        }
      }
    );
  }

  /**
   * 请求失败后的错误统一处理
   * @param status 请求失败的状态码
   * @param other
   */
  private errorHandle = (status: number, other: string) => {
    // 状态码判断
    switch (status) {
      case -1: // -1: 未登录状态,跳转登录页
        message("未登录状态");
        break;
      case 403: // 403 token过期
        message("登录过期,请重新登录");
        break;
      case 404: // 404请求不存在
        message("请求错误!!!");
        break;
      default:
        message(other);
    }
  };

  /**
   * get方法
   * @param url 路径
   * @param params 参数
   * @param config
   */
  public reqGet: Request = async (
    url: string,
    params?: unknown,
    config?: AxiosRequestConfig
  ) => {
    return await EnclosureHttp.axiosInstance.get(url, { params, ...config });
  };

  /**
   * post 方法
   * @param url 路径
   * @param params 参数
   * @param config
   */
  public reqPost: Request = (
    url: string,
    params: unknown = {},
    config?: AxiosRequestConfig
  ) => {
    return EnclosureHttp.axiosInstance.post(url, { data: params }, config);
  };

  /**
   * Axios init GET方法
   * @param url 路径
   * @param params 参数
   * @param config
   */
  public get: Request = (
    url: string,
    params?: unknown,
    config?: AxiosRequestConfig
  ) => {
    return Axios.get(url, { params, ...config });
  };

  /**
   * Axios init POST 方法
   * @param url 路径
   * @param params 参数
   * @param config
   */
  public post: Request = (
    url: string,
    params: unknown = {},
    config?: AxiosRequestConfig
  ) => {
    return Axios.post(url, { data: params }, config);
  };
}

export default EnclosureHttp;

type.ts  是类型和接口文件

import { AxiosRequestConfig } from "axios";

export interface IUser {
  name: string;
  pasword: string;
}

// 定制业务相关的网络请求响应格式, T 是具体的接口返回类型数据
export interface CustomSuccessData<T> {
  status: number;
  statusText: string;
  message?: string;
  data: T;
  [keys: string]: unknown;
}

/**
 *
 */
export interface Request {
  <T>(
    url: string,
    params?: Record<string, unknown>,
    config?: AxiosRequestConfig
  ): Promise<CustomSuccessData<T>>;
}

最后实际使用:拿网易云API 举例 

cloudMusic.ts 

import http from "@/utils/http";
import { Klyric, Rows, Songs } from "@/api/cloudMusic/types.ts";

const cloudBaseUrl = "https://autumnfish.cn/";
// const cloud = "/api";

/**
 * 网易云音乐开放接口的数据
 */
export class CloudApi {
  /*
   * 搜索音乐
   * @Params: {keywords} : 关键字
   * */
  static async searchMusic(params: { keywords: string }): Promise<Rows<Songs>> {
    const res = await http.reqGet<Rows<Songs>>(
      cloudBaseUrl + `/search`,
      params
    );
    return res.data;
  }

  /*
   * 获取音乐详情
   * @Params: {ids} : 音乐ID
   * */
  static async searchMusicDetail(params: { ids: number }) {
    return await http.reqGet(cloudBaseUrl + `/song/detail`, params);
  }

  /*
   * 获取歌词
   * @Params: {id} : 音乐ID
   * */
  static async getMusicLyric(params: { id: number }): Promise<Klyric> {
    const res = await http.reqGet<Klyric>(cloudBaseUrl + `/lyric`, params);
    return res.data;
  }

  /*
   * 获取音乐  -- 暂不可用
   * @Params: {id} : 音乐的ID
   * */
  static async getMusicUrl(params: { id: number }): Promise<unknown> {
    const res = await http.reqGet(cloudBaseUrl + `/song/url`, params);
    return res.data;
  }
}

types.ts 类型和接口

//搜索音乐 接口返回的数据类型
export interface Rows<T> {
  result?: Result<T>;
  code: number;
}

/**
 *搜索音乐返回的数据类型
 */
type Result<T> = {
  hasMore: boolean;
  songCount: number;
  songs: Array<T>;
};

/*
 *  获取的音乐列表
 * */
export interface Songs {
  album: album;
  alias: Array<string>;
  artists: Array<artist>;
  copyrightId: number;
  duration: number;
  fee: number;
  ftype: number;
  id: number;
  mark: number;
  mvid: number;
  name: string;
  rUrl: unknown;
  rtype: number;
  status: number;
}
/*
 *    //
 * */
type album = {
  artist: Array<artist>;
  copyrightId: number;
  id: number;
  mark: number;
  name: string;
  picId: number;
  publishTime: number;
  size: number;
  status: number;
};

/*
 *   //
 * */
type artist = {
  albumSize: number;
  alias: Array<unknown>;
  id: number;
  img1v1: number;
  img1v1Url: string;
  name: string;
  picId: number;
  picUrl: string;
  trans: string | number;
};

export interface Klyric {
  code: number;
  klyric: Lrc;
  lrc: Lrc;
  qfy: boolean;
  sfy: boolean;
  sgc: boolean;
  tlyric: Lrc;
}
export interface Lrc {
  lyric: string;
  version: number;
}

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐