一、class封装版
// 引入axios
import axios, {
AxiosInstance,
AxiosResponse,
Method,
ResponseType,
AxiosRequestConfig,
AxiosError
} from 'axios'
// 引入状态管理
import store from '@/store'
// 引入路由
import router from '@/router'
// 引入自定义工具
import { path, sleep } from "@/utils/means"
// 引入qs
import qs from 'qs'
// 引入封装的element-plus消息提示工具
import cue from '@/utils/cue'
export default class http {
private static axiosInstance: AxiosInstance
/** 是否已经初始化 */
private static flag: boolean = false
/**
* 初始化
* @returns
*/
private static init() {
if(this.flag) return
// console.log("初始化axios");
this.axiosInstance = axios.create({
baseURL: import.meta.env.VITE_RE_URL,
headers: {
'Content-Type': 'application/json;charset=utf-8',
},
timeout: 1000 * 30,
withCredentials: true,
})
this.initInterceptors()
this.flag = true
return axios
}
/**
* 初始化拦截器
*/
private static initInterceptors() {
// axios request 拦截器
this.axiosInstance.interceptors.request.use(
(config: AxiosRequestConfig) => {
//判断token是否存在
if (store.state.token != null) {
//将token设置成请求头
(config as any).headers.Authorization = store.state.token
}
return config
},
(error: AxiosError) => {
return Promise.reject(error)
}
)
// http response 拦截器
this.axiosInstance.interceptors.response.use((response: AxiosResponse) => {
// 只有 switch, 可用 return 直接结束返回
const res: IResult = response.data
switch (res.code) {
case 401: {
cue.notify.error({
title: '认证失败',
message: res.msg || '认证失败!请重试!'
})
break
}
case 402: {
store.commit('delete')
router.push(path('/login'))
cue.notify.error({
title: '登录过期',
message: res.msg || '登录信息已过期!请重新登录!'
})
// cue.error(res.msg)
break
}
case 403: {
cue.notify.error({
title: '权限验证',
message: res.msg || '您没有该操作权限!无法进行该操作!'
})
// cue.error(res.msg)
return response
}
case 404: {
cue.notify.error({
title: '请求出错',
message: res.msg || '不支持该请求方法!'
})
// cue.error(res.msg || '不支持该请求方法!')
break
}
case 405: {
cue.notify.error({
title: '重复请求',
message: res.msg || '请勿重复请求!'
})
// cue.error(res.msg || '请勿重复请求!')
break
}
case 500: {
cue.notify.error({
title: '服务器故障',
message: res.msg || '服务器故障!请重试!',
})
// cue.error(res.msg || '服务器故障,请重试')
break
}
default:
return response
}
}, (error: AxiosError) => {
return Promise.reject(error)
})
}
/**
* 请求
* @param method 方法
* @param params 参数集合
*/
private static request(method: Method, params: IReqParameter) {
const loading = cue.loading({
text: typeof params.loading == 'string' ? params.loading:undefined,
visible: params.loading ? true:false
})
params.timeout = params.timeout || 300
this.axiosInstance({
method: method,
url: params.url,
data: params.data,
responseType: params.resType
}).then((response: AxiosResponse) => {
sleep(params.timeout).then(() => {
loading.close()
})
if (!response) return
const res = response.data
if(res.code == 0) {
params.success?.(res)
} else if(res.code == 403) {
params.unauthorized?.(res)
} else {
if(params.error) {
params.error(res)
} else {
cue.notify.error({
title: '错误提示',
message: res.msg || '请求成功但发生错误,请检查!'
})
}
}
}).catch((error: AxiosError) => {
sleep(params.timeout).then(() => {
loading.close()
})
// console.log(error)
const { response } = error
// 状态码判断
if (response) {
const res: IResult = {
code: response.status,
msg: response.statusText,
data: response.data
}
switch (response.status) {
case 401:
break
case 403:
break
case 404:
res.msg = '请求的资源不存在'
cue.notify.error({
title: '请求出错',
message: res.msg,
})
break
default:
res.msg = '连接错误'
cue.notify.error({
title: '请求出错',
message: res.msg,
})
break
}
//params.error?.(res)
} else {
cue.notify.error({
title: '请求出错',
message: '网络连接异常,请稍后再试!',
})
}
})
}
/**
* 执行请求
* @param method 方法
* @param params 参数集合
*/
private static executeReq = (method: Method, params: IReqParameter) => {
this.init();
if (params.confirm) {
cue.confirm({
msg: typeof params.confirm == 'string' ? params.confirm:'确定进行该操作?',
ok: () => this.request(method, params)
})
} else {
this.request(method, params)
}
}
/**
* get请求
* @param params 参数集合
*/
public static get(params: IReqParameter){
if (params.data){
params.data = qs.stringify(JSON.parse(JSON.stringify(params.data)))
params.url = params.url + "?" + params.data
}
this.executeReq('GET', params)
}
/**
* post请求
* @param params 参数集合
*/
public static post(params: IReqParameter) {
this.executeReq('POST', params)
}
/**
* put请求
* @param params 参数集合
*/
public static put(params: IReqParameter){
this.executeReq('PUT', params)
}
/**
* delete请求
* @param params 参数集合
*/
public static delete(params: IReqParameter){
this.executeReq('DELETE', params)
}
/**
* 自定义请求
* @param method 方法
* @param params 参数集合
*/
public static custom(params: IReqParameterCustom) {
this.executeReq(params.method, params)
}
}
/**
* 后端返回的数据
* @key code 状态码
* @key data 数据
* @key msg 提示信息
* @key more 更多
*/
interface IResult {
code: number
data: any
msg: any
more?: any
}
/**
* 请求参数
* @key url 链接
* @key data 数据
* @key loading 是否开启 loading
* @key timeout loading持续时间
* @key confirm 是否需要confirm
* @key success 成功返回
* @key error 失败返回
* @key resType 返回类型
* @key unauthorized 无权限返回
*/
interface IReqParameter {
url: string
data?: any,
loading?: string | boolean
timeout?: number
confirm?: string | boolean
success?: (res: IResult) => void
error?: (err: IResult) => void
resType?: ResponseType
unauthorized?: (res: IResult) => void
}
/**
* 请求参数
* @key method 方法
*/
interface IReqParameterCustom extends IReqParameter {
method: Method
}
二、函数封装版
// 引入axios
import axios, {
AxiosResponse,
Method,
ResponseType,
AxiosRequestConfig,
AxiosError
} from 'axios'
// 引入状态管理
import store from '@/store'
// 引入路由
import router from '@/router'
// 引入自定义工具
import {path, sleep} from "@/utils/means"
// 引入qs
import qs from 'qs'
import cue from '@/utils/cue'
const http = axios.create({
baseURL: import.meta.env.VITE_RE_URL,
headers: {
'Content-Type': 'application/json',
},
timeout: 1000 * 30,
withCredentials: true,
})
// axios request 拦截器
http.interceptors.request.use(
(config: AxiosRequestConfig) => {
//判断token是否存在
if (store.state.token != null) {
//将token设置成请求头
(config as any).headers.Authorization = store.state.token
}
return config
},
(error: AxiosError) => {
return Promise.reject(error)
}
)
// http response 拦截器
http.interceptors.response.use((response: AxiosResponse) => {
// 只有 switch, 可用 return 直接结束返回
const res: IResult = response.data
switch (res.code) {
case 401: {
cue.notify.error({
title: '认证失败',
message: res.msg || '认证失败!请重试!'
})
break
}
case 402: {
store.commit('delete')
router.push(path('/login'))
cue.notify.error({
title: '登录过期',
message: res.msg || '登录信息已过期!请重新登录!'
})
// cue.error(res.msg)
break
}
case 403: {
cue.notify.error({
title: '权限验证',
message: res.msg || '您没有该操作权限!无法进行该操作!'
})
// cue.error(res.msg)
return response
}
case 404: {
cue.notify.error({
title: '请求出错',
message: res.msg || '不支持该请求方法!'
})
// cue.error(res.msg || '不支持该请求方法!')
break
}
case 405: {
cue.notify.error({
title: '重复请求',
message: res.msg || '请勿重复请求!'
})
// cue.error(res.msg || '请勿重复请求!')
break
}
case 500: {
cue.notify.error({
title: '服务器故障',
message: res.msg || '服务器故障!请重试!',
})
// cue.error(res.msg || '服务器故障,请重试')
break
}
default:
return response
}
}, (error: AxiosError) => {
return Promise.reject(error)
})
/**
* 请求
* @param method 方法
* @param params 参数集合
*/
const request = (method: Method, params: IReqParameter) => {
const loading = cue.loading({
text: typeof params.loading == 'string' ? params.loading:undefined,
visible: params.loading ? true:false
})
params.timeout = params.timeout || 300
http({
method: method,
url: params.url,
data: params.data,
responseType: params.resType
}).then((response: AxiosResponse) => {
sleep(params.timeout).then(() => {
loading.close()
})
if (!response) return
const res = response.data
if(res.code == 0) {
params.success?.(res)
} else if(res.code == 403) {
params.unauthorized?.(res)
} else {
params.error?.(res)
}
}).catch((error: AxiosError) => {
sleep(params.timeout).then(() => {
loading.close()
})
// console.log(error)
const { response } = error
// 状态码判断
if (response) {
const res: IResult = {
code: response.status,
msg: response.statusText,
data: response.data
}
switch (response.status) {
case 401:
break
case 403:
break
case 404:
res.msg = '请求的资源不存在'
cue.notify.error({
title: '请求出错',
message: res.msg,
})
break
default:
res.msg = '连接错误'
cue.notify.error({
title: '请求出错',
message: res.msg,
})
break
}
params.error?.(res)
} else {
cue.notify.error({
title: '请求出错',
message: '网络连接异常,请稍后再试!',
})
}
})
}
/**
* 执行请求
* @param method 方法
* @param params 参数集合
*/
const executeReq = (method: Method, params: IReqParameter) => {
if (params.confirm) {
cue.confirm({
msg: typeof params.confirm == 'string' ? params.confirm:'确定进行该操作?',
ok: () => request(method, params)
})
} else {
request(method, params)
}
}
/**
* 后端返回数据
* @key code 状态码
* @key data 数据
* @key msg 提示信息
*/
interface IResult {
code: number
data: any
msg: any
more?: any
}
/**
* 请求参数
* @key url 链接
* @key data 数据
* @key loading 是否开启 loading
* @key timeout loading持续时间
* @key confirm 是否需要confirm
* @key success 成功返回
* @key error 失败返回
* @key resType 返回类型
* @key unauthorized 无权限返回
*/
interface IReqParameter {
url: string
data?: any,
loading?: string | boolean
timeout?: number
confirm?: string | boolean
success?: (res: IResult) => void
error?: (err: IResult) => void
resType?: ResponseType
unauthorized?: (res: IResult) => void
}
/**
* 请求参数
* @key method 方法
*/
interface IReqParameterCustom extends IReqParameter {
method: Method
}
export default {
/**
* get请求
* @param params 参数集合
*/
get(params: IReqParameter){
if (params.data){
params.data = qs.stringify(JSON.parse(JSON.stringify(params.data)))
params.url = params.url + "?" + params.data
}
executeReq('GET', params)
},
/**
* post请求
* @param params 参数集合
*/
post(params: IReqParameter) {
executeReq('POST', params)
},
/**
* put请求
* @param params 参数集合
*/
put(params: IReqParameter){
executeReq('PUT', params)
},
/**
* delete请求
* @param params 参数集合
*/
delete(params: IReqParameter){
executeReq('DELETE', params)
},
/**
* 自定义请求
* @param method 方法
* @param params 参数集合
*/
custom(params: IReqParameterCustom) {
executeReq(params.method, params)
}
}
三、使用方法
两种封装方式使用方法一样,具体使用如下(可自行统一封装所有的api):
<template>
<el-button type="primary" @click="login">冲鸭</el-button>
</template>
<script setup lang='ts'>
import { getCurrentInstance, ComponentPublicInstance } from 'vue';
// 加上以下的配置(四、全局配置,使全局实例出现代码提示),即可出现全局代码提示
const proxy = getCurrentInstance()?.proxy as ComponentPublicInstance
const login = () => {
proxy.$http.post({
url: '/system/login',
loading: '正在登录...',
data: {
username: 'admin',
password: '123456789',
code: '123456'
},
success: (res) => {
console.log(res);
proxy.$cue.success('成功')
},
error: (res: any) => {
console.log(res);
proxy.$cue.notify.error({
title: '登录提示',
message: res.msg
})
}
})
}
</script>
<style scoped lang='scss'>
</style>
四、全局配置,使全局实例出现代码提示
4.1、globalInstance.ts
import { App } from 'vue'
import http from '@/utils/http'
import cue from '@/utils/cue'
import toTree from '@/utils/toTree'
import { sleep, debounce, path, md5 } from '@/utils/means'
export default {
install: (app: App) => {
app.config.globalProperties.$http = http
app.config.globalProperties.$cue = cue
app.config.globalProperties.$toTree = toTree
app.config.globalProperties.$sleep = sleep
app.config.globalProperties.$debounce = debounce
app.config.globalProperties.$path = path
app.config.globalProperties.$md5 = md5
}
}
// 必须要加 否则不会有代码提示
declare module '@vue/runtime-core' {
interface ComponentCustomProperties {
$http: typeof http
$cue: typeof cue
$toTree: typeof toTree
$sleep: typeof sleep
$debounce: typeof debounce
$path: typeof path
$md5: typeof md5
}
}
4.2、main.ts
import { createApp } from 'vue'
import App from './App.vue'
// 路由
import router from '@/router'
// 状态
import store from '@/store'
// 路由拦截
import '@/router/router'
import icons from '@/utils/icons'
// 全局实例
import globalInstance from '@/utils/globalInstance'
const app = createApp(App)
app.use(router)
.use(store)
.use(icons)
.use(globalInstance)
.mount('#app')
提示:const proxy = getCurrentInstance()?.proxy as ComponentPublicInstance
并不知道在线上会不会有什么问题,没有试过,慎用!