前端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的关键在于对于业务的统一性,方便进行管理