前端vue3+ts基于axios的二次封装

752 阅读2分钟

前端vue3+ts基于axios的二次封装

前言:最近面试经常会问到如何二次封装axios的问题,其实每个项目的封装都不太一样,但是基本思路是一样的,需要我们结合自己具体的项目去封装,下面是我在自己的项目中用到的封装axios的一些步骤。

下载安装依赖

npm install axios --save

新建axios配置文件

因为我本人项目是ts的,所以会定义很多接口,类型

图片

封装axios,这一步可以根据自己的业务进行灵活配置

import axios, { AxiosResponse, AxiosRequestConfig, Axios } from 'axios'import { ResultEnum, ModuleTypeEnum } from '@/enums/httpEnum'import { PageEnum, ErrorPageNameMap } from '@/enums/pageEnum'import { StorageEnum } from '@/enums/storageEnum'import { SystemStoreEnum, SystemStoreUserInfoEnum } from '@/store/modules/systemStore/systemStore.d'import includes from 'lodash/includes'

export interface MyResponseType<T> {  code?: ResultEnum  data: T  message?: string  status: boolean  msg?: string}

export interface MyRequestInstance extends Axios {  <T = any>(config: AxiosRequestConfig): Promise<MyResponseType<T>>}//声明axios实例const axiosInstance = axios.create({  baseURL: `xxx`,  timeout: ResultEnum.TIMEOUT}) as unknown as MyRequestInstance

// 请求拦截器,主要处理请求前的逻辑,比如往接口传参数,token鉴权等axiosInstance.interceptors.request.use(  (config: AxiosRequestConfig) => {    let mergedObj: any = {}    const paramsName: any = decodeURIComponent(window.location.hash.split('?')[1])    if (paramsName) {      const searchParams = new URLSearchParams(paramsName)      const paramsObject = Object.fromEntries(searchParams.entries())      const tokenObj = {        [paramsObject.tokenName]: paramsObject.tokenValue      }

      mergedObj = Object.assign({}, tokenObj)    }

    config.headers = {      ...config.headers,      ...mergedObj,    }

    return config  },  (err: AxiosRequestConfig) => {    Promise.reject(err)  })

// 响应拦截器,处理一些业务逻辑axiosInstance.interceptors.response.use(  (res: AxiosResponse) => {    // 预览页面错误不进行处理    if (isPreview()) {      return Promise.resolve(res.data)    }    const { code, status } = res.data as { code: number; status: boolean; msg: string }

    if (code === undefined || code === null) return Promise.resolve(res.data)

    // 成功    if (status) {      return Promise.resolve(res.data)    }       // 固定错误码重定向    if (ErrorPageNameMap.get(code)) {      redirectErrorPage(code)      return Promise.resolve(res.data)    }

    // 提示错误    window['$message'].error(window['$t']((res.data as any).msg))    return Promise.resolve(res.data)  },  //根据业务不同的状态码对应不同的提示,全局提示  (err: any) => {    if (includes(fetchAllowList,err.config.url)){      if (err.response.status == 401) {        window['$message'].error(window['$t']('http.token_overdue_message'))        routerTurnByName(PageEnum.BASE_LOGIN_NAME)      } else {        if (err.response.data.code == 'A0231') {          window['$message'].error('您的账号已被禁止访问,请重新登录')          routerTurnByName(PageEnum.BASE_LOGIN_NAME)        } else if (err.response.data.code == 'A0232') {          window['$message'].error('您的账号已在其他地方登录,请重新登录')          routerTurnByName(PageEnum.BASE_LOGIN_NAME)        } else {          window['$message'].error(window['$t'](err.response.data.msg))        }      }    }else{      window['$message'].error(window['$t'](err.response.data.msg))    }   

    Promise.reject(err)  })

//抛出axios实例export default axiosInstance

如果你不需要再一步配置的话,可以直接在path.ts里面写请求了,

import axiosInstance from './axios'

export const get = <T = any>(url: string, params?: object) => {  return axiosInstance<T>({    url: url,    method: 'get',    params: params  })}

到此,最简单的封装axios基本就完成了,但是为了代码更佳的统一,最好在封装一层http.ts,如下所示:

http.ts
import axiosInstance from './axios'import axios from 'axios'import {  RequestHttpEnum,  ContentTypeEnum,  RequestBodyEnum,  RequestDataTypeEnum,  RequestContentTypeEnum,  RequestParamsObjType} from '@/enums/httpEnum'import type { RequestGlobalConfigType, RequestConfigType } from '@/store/modules/chartEditStore/chartEditStore.d'

export const get = <T = any>(url: string, params?: object) => {  return axiosInstance<T>({    url: url,    method: RequestHttpEnum.GET,    params: params  })}

export const post = <T = any>(url: string, data?: object, params?: object, headers?: any) => {  return axiosInstance<T>({    url: url,    method: RequestHttpEnum.POST,    data: data,    params: params,

    headers: headers  })}

export const patch = <T = any>(url: string, data?: object, headersType?: string) => {  return axiosInstance<T>({    url: url,    method: RequestHttpEnum.PATCH,    data: data,    headers: {      'Content-Type': headersType || ContentTypeEnum.JSON    }  })}

export const put = <T = any>(url: string, data?: object, params?: object, headersType?: ContentTypeEnum) => {  return axiosInstance<T>({    url: url,    method: RequestHttpEnum.PUT,    data: data,    params: params,    headers: {      'Content-Type': headersType || ContentTypeEnum.JSON    }  })}

export const del = <T = any>(url: string, params?: object) => {  return axiosInstance<T>({    url: url,    method: RequestHttpEnum.DELETE,    params  })}

// 获取请求函数,默认getexport const http = (type?: RequestHttpEnum) => {  switch (type) {    case RequestHttpEnum.GET:      return get

    case RequestHttpEnum.POST:      return post

    case RequestHttpEnum.PATCH:      return patch

    case RequestHttpEnum.PUT:      return put

    case RequestHttpEnum.DELETE:      return del

    default:      return get  }}
path.ts


import { http, request } from '@/api/http'import { httpErrorHandle } from '@/utils'import { ContentTypeEnum, RequestHttpEnum, ModuleTypeEnum } from '@/enums/httpEnum'import { ProjectItem, ProjectDetail, ProjectList } from './project'import { AnyARecord } from 'dns'

// * 项目列表export const projectListApi = async (data: object) => {  try {    const res = await http(RequestHttpEnum.POST)(`${ModuleTypeEnum.PROJECT}/Bi/homeList`, data)    return res  } catch {    httpErrorHandle()  }}

到此二次封装axios的步骤就结束了,封装axios的关键在于对于业务的统一性,方便进行管理