说明:axios负责发送请求,mockjs负责便捷构造响应数据,vite-plugin-mock负责代理axios数据请求到本地
npm i axios mockjs vite-plugin-mock
2.封装axios
import axios from 'axios'
import type {
AxiosInstance,
AxiosError,
AxiosRequestConfig,
AxiosResponse,
} from 'axios'
import { ElMessage } from 'element-plus'
import { useUserStore } from '@/store/modules/user'
import { ResultEnum } from '@/enums/httpEnums'
import { ResultData } from './type'
import { LOGIN_URL } from '@/config/config'
import { RESEETSTORE } from '../reset'
import router from '@/router'
import { initMock } from '@/mock/mock'
export enum ResultEnum {
SUCCESS = 200,
EXPIRE = 203,
ERROR = -1,
ERRMESSAGE = '请求失败',
TIMEOUT = 25000,
TYPE = 'success',
}
export const service: AxiosInstance = axios.create({
// 判断环境设置不同的baseURL
baseURL:
import.meta.env.NODE_ENV === 'development'
? import.meta.env.VITE_APP_BASE_API
: import.meta.env.VITE_APP_BASE_URL,
timeout: ResultEnum.TIMEOUT as number,
})
// 根据配置决定是否使用mock
if (import.meta.env?.VITE_APP_OPEN_MOCK?.toString() === 'true') {
// 初始化mock,axios-mock-adapter
console.log('初始化mock,axios-mock-adapter')
initMock(service)
}
/**
* @description: 请求拦截器
* @returns {*}
*/
service.interceptors.request.use(
(config) => {
const userStore = useUserStore()
const token = userStore.token
if (token) {
config.headers.token = token
}
return config
},
(error: AxiosError) => {
ElMessage.error(error.message)
return Promise.reject(error)
},
)
/**
* @description: 响应拦截器
* @returns {*}
*/
service.interceptors.response.use(
(response: AxiosResponse) => {
const { data } = response
// * 登陆失效(code == 203)
if (data.code === ResultEnum.EXPIRE) {
RESEETSTORE()
ElMessage.error(data.message || ResultEnum.ERRMESSAGE)
router.replace(LOGIN_URL)
return Promise.reject(data)
}
if (data.code && data.code !== ResultEnum.SUCCESS) {
ElMessage.error(data.message || ResultEnum.ERRMESSAGE)
return Promise.reject(data)
}
return data
},
(error: AxiosError) => {
// 处理 HTTP 网络错误
let message = ''
// HTTP 状态码
const status = error.response?.status
switch (status) {
case 401:
message = 'token 失效,请重新登录'
break
case 403:
message = '拒绝访问'
break
case 404:
message = '请求地址错误'
break
case 500:
message = '服务器故障'
break
default:
message = '网络连接故障'
}
ElMessage.error(message)
return Promise.reject(error)
},
)
/**
* @description: 导出封装的请求方法
* @returns {*}
*/
const http = {
get<T>(
url: string,
params?: object,
config?: AxiosRequestConfig,
): Promise<ResultData<T>> {
return service.get(url, { params, ...config })
},
post<T>(
url: string,
data?: object,
config?: AxiosRequestConfig,
): Promise<ResultData<T>> {
return service.post(url, data, config)
},
put<T>(
url: string,
data?: object,
config?: AxiosRequestConfig,
): Promise<ResultData<T>> {
return service.put(url, data, config)
},
delete<T>(
url: string,
data?: object,
config?: AxiosRequestConfig,
): Promise<ResultData<T>> {
return service.delete(url, { data, ...config })
},
}
export default http
额外封装一个用于mock请求的axios,这样可以很方便针对请求单独进行mock,而不必全局mock,与上面的axios实例唯一不同的就是baseUrl蚕食,这个/mock,与下面的all.ts最后暴露出去的数组前缀相关联,最后只要是使用这个axios的请求的都会从mock请求
3.具体实现代码
目录结构:
1._utils.ts
/**
* @description: 响应结果
* @argument SUCCESS 请求成功
* @argument EXPIRE token请求失效或校验失败
* @argument ERROR 请求错误
* @argument TIMEOUT 请求超时
* @argument TYPE 请求类型
*/
export const ResultEnum = {
SUCCESS: 200,
EXPIRE: [501, 601, 602],
ERROR: -1,
ERRMESSAGE: '请求失败',
TIMEOUT: 25000,
TYPE: 'success',
} as const;
/**
* @description: 错误响应结构
* @returns {*}
*/
export function resultError(message = 'Request failed', { code = ResultEnum.ERROR, data = null } = {}) {
return {
code,
data,
msg:message,
type: 'error',
};
}
/**
* @description: 成功响应结构
* @returns {*}
*/
export function resultSuccess<T>(data: T, { message = 'ok' } = {}) {
return {
code: ResultEnum.SUCCESS,
data,
msg:message,
type: 'success',
};
}
export interface requestParams {
method: string;
body: any;
headers?: { token?: string };
query: any;
}
/**
* @description 本函数用于从request数据中获取token,请根据项目的实际情况修改
* @return token
*/
export function getRequestToken({ headers }: requestParams): string | undefined {
return headers?.token;
}
2._all.ts
import { resultSuccess } from './_utils';
import Mock from 'mockjs';
import { MockMethod } from 'vite-plugin-mock'
const mockApiList = [
//#region <视频图像标注>
// 获取摄像头项目列表
{
url: "/admin/cameraProject/cameraList/:projectId",
method: "get",
response: (request: any) => {
const { data } = Mock.mock({
"data|4-10": [
{
"cameraId|+1": 1,
"cameraName": "@ctitle(5, 10)",
}
]
});
return resultSuccess(data);
}
},
// 视频抽取图片
{
url: "/admin/cameraDailyVideo/extract",
method: "post",
response: (request: any) => {
return resultSuccess(
{
"businessFilesId": 1,
"url": "@image(1920x1080)",
"fullUrl": "@image(1920x1080)",
"pictureName": "@ctitle(5, 10)",
"pictureTime": "@date(yyyy-MM-dd)",
"cameraName": "@ctitle(5, 10)",
}
);
}
},
// 新增班组影像
{
url: "/admin/teamPicture/addTeamPicture",
method: "post",
response: (request: any) => {
return resultSuccess(
true
);
}
},
//#endregion
] as MockMethod[];
export default mockApiList.map((item: any) => {
return {
...item,
url: `/mock${item.url}`,
};
});
4.配置vite.config
增加配置
// 便于复制
import { viteMockServe } from 'vite-plugin-mock';
viteMockServe(),