mirror of
https://github.com/m-xlsea/ruoyi-plus-soybean.git
synced 2025-09-24 07:49:47 +08:00
refactor(projects): 请求函数重构初步
This commit is contained in:
@ -3,20 +3,22 @@ import { ref } from 'vue';
|
||||
export default function useBoolean(initValue: boolean = false) {
|
||||
const bool = ref(initValue);
|
||||
|
||||
function setBool(value: boolean) {
|
||||
bool.value = value;
|
||||
}
|
||||
function setTrue() {
|
||||
bool.value = true;
|
||||
setBool(true);
|
||||
}
|
||||
|
||||
function setFalse() {
|
||||
bool.value = false;
|
||||
setBool(false);
|
||||
}
|
||||
|
||||
function toggle() {
|
||||
bool.value = !bool.value;
|
||||
setBool(!bool.value);
|
||||
}
|
||||
|
||||
return {
|
||||
bool,
|
||||
setBool,
|
||||
setTrue,
|
||||
setFalse,
|
||||
toggle
|
||||
|
@ -0,0 +1 @@
|
||||
export {};
|
||||
|
1
src/service/api/index.ts
Normal file
1
src/service/api/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './auth';
|
@ -0,0 +1 @@
|
||||
export * from './api';
|
||||
|
@ -0,0 +1 @@
|
||||
export function handleResponse() {}
|
||||
|
1
src/service/middleware/index.ts
Normal file
1
src/service/middleware/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './auth';
|
8
src/service/request/axios/index.ts
Normal file
8
src/service/request/axios/index.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import type { AxiosRequestConfig } from 'axios';
|
||||
import CustomAxiosInstance from './instance';
|
||||
import Request from './request';
|
||||
|
||||
export function createRequest(axiosConfig: AxiosRequestConfig) {
|
||||
const customInstance = new CustomAxiosInstance(axiosConfig);
|
||||
return new Request(customInstance.instance);
|
||||
}
|
@ -1,9 +1,7 @@
|
||||
import axios from 'axios';
|
||||
import qs from 'qs';
|
||||
import type { AxiosRequestConfig, AxiosInstance } from 'axios';
|
||||
import { ContentType } from '@/enum';
|
||||
import type { AxiosRequestConfig, AxiosInstance, CancelTokenStatic } from 'axios';
|
||||
import { getToken } from '@/utils';
|
||||
import { transformFile, errorHandler } from '../utils';
|
||||
import { transformRequestData, handleResponseError } from '../helpers';
|
||||
|
||||
export interface StatusConfig {
|
||||
/** 表明请求状态的属性key */
|
||||
@ -16,54 +14,47 @@ export interface StatusConfig {
|
||||
|
||||
/**
|
||||
* 封装axios请求类
|
||||
* @author Soybean(曹理斌) 2021-03-13
|
||||
* @class CustomAxiosInstance
|
||||
* @author Soybean<honghuangdc@gmail.com> 2021-03-13
|
||||
*/
|
||||
export default class CustomAxiosInstance {
|
||||
instance: AxiosInstance;
|
||||
|
||||
constructor(
|
||||
axiosConfig: AxiosRequestConfig,
|
||||
statusConfig: StatusConfig = {
|
||||
cancelToken: CancelTokenStatic;
|
||||
|
||||
private statusConfig: StatusConfig = {
|
||||
statusKey: 'code',
|
||||
msgKey: 'message',
|
||||
successCode: 200
|
||||
}
|
||||
) {
|
||||
};
|
||||
|
||||
constructor(axiosConfig: AxiosRequestConfig) {
|
||||
this.instance = axios.create(axiosConfig);
|
||||
this.setInterceptor(statusConfig);
|
||||
this.cancelToken = axios.CancelToken;
|
||||
this.setInterceptor();
|
||||
}
|
||||
|
||||
/** 设置请求拦截器 */
|
||||
setInterceptor(statusConfig: StatusConfig): void {
|
||||
setInterceptor(): void {
|
||||
this.instance.interceptors.request.use(
|
||||
async config => {
|
||||
const handleConfig = { ...config };
|
||||
if (handleConfig.headers) {
|
||||
// form类型转换
|
||||
if (handleConfig.headers['Content-Type'] === ContentType.formUrlencoded) {
|
||||
handleConfig.data = qs.stringify(handleConfig.data);
|
||||
}
|
||||
// 文件类型转换
|
||||
if (handleConfig?.headers['Content-Type'] === ContentType.formData) {
|
||||
const key = Object.keys(handleConfig.data)[0];
|
||||
const file = handleConfig.data[key];
|
||||
handleConfig.data = await transformFile(file, key);
|
||||
}
|
||||
// 数据转换
|
||||
handleConfig.data = await transformRequestData(handleConfig.data, handleConfig.headers['Content-Type']);
|
||||
// 设置token
|
||||
handleConfig.headers.Authorization = getToken();
|
||||
}
|
||||
return handleConfig;
|
||||
},
|
||||
error => {
|
||||
errorHandler(error);
|
||||
handleResponseError(error);
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
this.instance.interceptors.response.use(
|
||||
response => {
|
||||
const { status, data } = response;
|
||||
const { statusKey, msgKey, successCode } = statusConfig;
|
||||
const { statusKey, msgKey, successCode } = this.statusConfig;
|
||||
if (status === 200 || status < 300 || status === 304) {
|
||||
const responseData = data as any;
|
||||
if (responseData[statusKey] === successCode) {
|
||||
@ -73,11 +64,11 @@ export default class CustomAxiosInstance {
|
||||
return Promise.reject(responseData[msgKey]);
|
||||
}
|
||||
const error = { response };
|
||||
errorHandler(error);
|
||||
handleResponseError(error);
|
||||
return Promise.reject(error);
|
||||
},
|
||||
error => {
|
||||
errorHandler(error);
|
||||
handleResponseError(error);
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
@ -1,6 +1,4 @@
|
||||
import type { AxiosRequestConfig, AxiosInstance, AxiosResponse } from 'axios';
|
||||
import CustomAxiosInstance from './instance';
|
||||
import type { StatusConfig } from './instance';
|
||||
|
||||
type ResponseSuccess = [null, any];
|
||||
type ResponseFail = [any, null];
|
||||
@ -10,7 +8,7 @@ type ResponseFail = [any, null];
|
||||
* @author Soybean<honghuangdc@gmail.com> 2021-03-15
|
||||
* @class Request
|
||||
*/
|
||||
class Request {
|
||||
export default class Request {
|
||||
instance: AxiosInstance;
|
||||
|
||||
constructor(instance: AxiosInstance) {
|
||||
@ -44,8 +42,37 @@ class Request {
|
||||
}
|
||||
}
|
||||
|
||||
export function createRequest(axiosConfig: AxiosRequestConfig, statusConfig?: StatusConfig) {
|
||||
const customInstance = new CustomAxiosInstance(axiosConfig, statusConfig);
|
||||
const request = new Request(customInstance.instance);
|
||||
return request;
|
||||
}
|
||||
// import type { AxiosRequestConfig, AxiosInstance } from 'axios';
|
||||
// import { useBoolean } from '@/hooks';
|
||||
|
||||
// type RequestMethod = 'get' | 'post' | 'put' | 'delete';
|
||||
|
||||
// interface RequestParam<ResponseData> {
|
||||
// /** axios实例 */
|
||||
// instance: AxiosInstance;
|
||||
// /** 请求地址 */
|
||||
// url: string;
|
||||
// /** 请求方法 */
|
||||
// method?: RequestMethod;
|
||||
// /** axios请求配置 */
|
||||
// axiosConfig?: AxiosRequestConfig;
|
||||
// /** 请求结果的数据判断是否为空的函数 */
|
||||
// responseDataEmptyFunc?: (data: ResponseData) => boolean;
|
||||
// /** 全局请求错误时是否弹出消息 */
|
||||
// showErrorMsg?: boolean;
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * 请求函数hooks
|
||||
// * @param requestParam - 请求函数的参数
|
||||
// * @param url - 请求地址
|
||||
// * @param axiosConfig
|
||||
// */
|
||||
// export default function useRequest<ResponseData>(requestParam: RequestParam<ResponseData>) {
|
||||
// /** 网络状况 */
|
||||
// const { bool: networkStatus, setBool: setNetworkStatus } = useBoolean(window.navigator.onLine);
|
||||
// /** 是否正在请求 */
|
||||
// const { bool: isFetching, setBool: setIsFetching } = useBoolean();
|
||||
// /** 响应的结果数据是否为空 */
|
||||
// const { bool: isEmpty, setBool: setIsEmpty } = useBoolean();
|
||||
// }
|
50
src/service/request/helpers/error.ts
Normal file
50
src/service/request/helpers/error.ts
Normal file
@ -0,0 +1,50 @@
|
||||
const ERROR_STATUS = {
|
||||
400: '400: 请求出现语法错误',
|
||||
401: '401: 用户未授权~',
|
||||
403: '403: 服务器拒绝访问~',
|
||||
404: '404: 请求的资源不存在~',
|
||||
405: '405: 请求方法未允许~',
|
||||
408: '408: 网络请求超时~',
|
||||
500: '500: 服务器内部错误~',
|
||||
501: '501: 服务器未实现请求功能~',
|
||||
502: '502: 错误网关~',
|
||||
503: '503: 服务不可用~',
|
||||
504: '504: 网关超时~',
|
||||
505: '505: http版本不支持该请求~'
|
||||
};
|
||||
|
||||
type ErrorStatus = keyof typeof ERROR_STATUS;
|
||||
|
||||
type ErrorMsg = [boolean, string];
|
||||
/**
|
||||
* 获取请求失败的错误
|
||||
* @param error
|
||||
*/
|
||||
export function getFailRequestErrorMsg(error: any) {
|
||||
const errorAction: ErrorMsg[] = [
|
||||
[!window.navigator.onLine || error.message === 'Network Error', '网络不可用~'],
|
||||
[error.code === 'ECONNABORTED' && error.message.includes('timeout'), '网络连接超时~'],
|
||||
[error.response, ERROR_STATUS[error.response.status as ErrorStatus]]
|
||||
];
|
||||
let errorMsg = '请求错误~';
|
||||
errorAction.some(item => {
|
||||
const [flag, msg] = item;
|
||||
if (flag) {
|
||||
errorMsg = msg;
|
||||
}
|
||||
return flag;
|
||||
});
|
||||
return errorMsg;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理请求失败的错误
|
||||
* @param error - 错误
|
||||
*/
|
||||
export function handleResponseError(error: any) {
|
||||
const { $message: Message } = window;
|
||||
|
||||
const msg = getFailRequestErrorMsg(error);
|
||||
|
||||
Message?.error(msg);
|
||||
}
|
16
src/service/request/helpers/handler.ts
Normal file
16
src/service/request/helpers/handler.ts
Normal file
@ -0,0 +1,16 @@
|
||||
// type ResultHandler<T> = (...arg: any) => T;
|
||||
// type SuccessRequest<T> = {
|
||||
// error: null;
|
||||
// data: T;
|
||||
// };
|
||||
// type FailRequest = {
|
||||
// error: any;
|
||||
// data: null;
|
||||
// };
|
||||
// type RequestResult<T> = SuccessRequest<T> | FailRequest;
|
||||
// /**
|
||||
// * 对请求的结果数据进行格式化的处理
|
||||
// * @param handleFunc - 处理函数
|
||||
// * @param requests - 请求结果
|
||||
// */
|
||||
// export function handleResponse<ResponseData>(resultHandler: ResultHandler<ResponseData>, requests: RequestResult[]) {}
|
2
src/service/request/helpers/index.ts
Normal file
2
src/service/request/helpers/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export * from './transform';
|
||||
export * from './error';
|
40
src/service/request/helpers/transform.ts
Normal file
40
src/service/request/helpers/transform.ts
Normal file
@ -0,0 +1,40 @@
|
||||
import qs from 'qs';
|
||||
import FormData from 'form-data';
|
||||
import { isArray } from '@/utils';
|
||||
import { ContentType } from '@/enum';
|
||||
|
||||
export async function transformRequestData(requestData: any, contentType?: string) {
|
||||
// application/json类型不处理
|
||||
let data = requestData;
|
||||
// form类型转换
|
||||
if (contentType === ContentType.formUrlencoded) {
|
||||
data = qs.stringify(requestData);
|
||||
}
|
||||
// form-data类型转换
|
||||
if (contentType === ContentType.formData) {
|
||||
const key = Object.keys(requestData)[0];
|
||||
const file = requestData.data[key];
|
||||
data = await transformFile(file, key);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 接口为上传文件的类型时数据转换
|
||||
* @param file - 单文件或多文件
|
||||
* @param key - 文件的属性名
|
||||
*/
|
||||
async function transformFile(file: File[] | File, key: string) {
|
||||
const formData = new FormData();
|
||||
if (isArray(file)) {
|
||||
await Promise.all(
|
||||
(file as File[]).map(item => {
|
||||
formData.append(key, item);
|
||||
return true;
|
||||
})
|
||||
);
|
||||
} else {
|
||||
await formData.append(key, file);
|
||||
}
|
||||
return formData;
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
import { createRequest } from './request';
|
||||
import { createRequest } from './axios';
|
||||
|
||||
export const adminRequest = createRequest({
|
||||
baseURL: import.meta.env.VITE_HTTP_URL_EMOSS_ADMIN as string
|
||||
|
@ -1,121 +0,0 @@
|
||||
import FormData from 'form-data';
|
||||
import { isArray } from '@/utils';
|
||||
|
||||
type HandleFunc<T> = (...arg: any) => T;
|
||||
type RequestError = any;
|
||||
type RequestData = any;
|
||||
type RequestResult = [RequestError, RequestData];
|
||||
/**
|
||||
* 对请求的结果数据进行格式化的处理
|
||||
* @param handleFunc - 处理函数
|
||||
* @param requests - 请求结果
|
||||
*/
|
||||
export function handleResponse<T>(handleFunc: HandleFunc<T>, ...requests: RequestResult[]) {
|
||||
let handleData: any = null;
|
||||
let error: any = null;
|
||||
const hasError = requests.some(item => {
|
||||
const isError = Boolean(item[0]);
|
||||
if (isError) {
|
||||
[error] = item;
|
||||
}
|
||||
return isError;
|
||||
});
|
||||
if (!hasError) {
|
||||
handleData = handleFunc(...requests.map(item => item[1]));
|
||||
}
|
||||
return [error, handleData] as [any, T];
|
||||
}
|
||||
|
||||
/**
|
||||
* 接口为上传文件的类型时数据转换
|
||||
* @param file - 单文件或多文件
|
||||
* @param key - 文件的属性名
|
||||
*/
|
||||
export async function transformFile(file: File[] | File, key: string) {
|
||||
const formData = new FormData();
|
||||
if (isArray(file)) {
|
||||
await Promise.all(
|
||||
(file as File[]).map(item => {
|
||||
formData.append(key, item);
|
||||
return true;
|
||||
})
|
||||
);
|
||||
} else {
|
||||
await formData.append(key, file);
|
||||
}
|
||||
return formData;
|
||||
}
|
||||
|
||||
const ERROR_STATUS = {
|
||||
400: '400: 请求出现语法错误',
|
||||
401: '401: 用户未授权~',
|
||||
403: '403: 服务器拒绝访问~',
|
||||
404: '404: 请求的资源不存在~',
|
||||
405: '405: 请求方法未允许~',
|
||||
408: '408: 网络请求超时~',
|
||||
500: '500: 服务器内部错误~',
|
||||
501: '501: 服务器未实现请求功能~',
|
||||
502: '502: 错误网关~',
|
||||
503: '503: 服务不可用~',
|
||||
504: '504: 网关超时~',
|
||||
505: '505: http版本不支持该请求~'
|
||||
};
|
||||
type ErrorStatus = keyof typeof ERROR_STATUS;
|
||||
|
||||
/**
|
||||
* 网络请求错误状态处理
|
||||
* @param error - 错误
|
||||
*/
|
||||
export function errorHandler(error: any): void {
|
||||
const { $message: Message } = window;
|
||||
if (error.response) {
|
||||
const status = error.response.status as ErrorStatus;
|
||||
Message?.error(ERROR_STATUS[status]);
|
||||
return;
|
||||
}
|
||||
if (error.code === 'ECONNABORTED' && error.message.includes('timeout')) {
|
||||
Message?.error('网络连接超时~');
|
||||
return;
|
||||
}
|
||||
if (!window.navigator.onLine || error.message === 'Network Error') {
|
||||
Message?.error('网络不可用~');
|
||||
return;
|
||||
}
|
||||
Message?.error('请求错误~');
|
||||
}
|
||||
|
||||
/**
|
||||
* 连续的请求错误依此显示
|
||||
* @param duration - 上一次弹出错误消息到下一次的时间(ms)
|
||||
*/
|
||||
export function continuousErrorHandler(duration: number) {
|
||||
let errorStacks: string[] = [];
|
||||
function pushError(id: string) {
|
||||
errorStacks.push(id);
|
||||
}
|
||||
function removeError(id: string) {
|
||||
errorStacks = errorStacks.filter(item => item !== id);
|
||||
}
|
||||
function handleError(id: string, callback: Function) {
|
||||
callback();
|
||||
setTimeout(() => {
|
||||
removeError(id);
|
||||
}, duration);
|
||||
}
|
||||
|
||||
function handleContinuousError(callback: Function) {
|
||||
const id = Date.now().toString(36);
|
||||
const { length } = errorStacks;
|
||||
if (length > 0) {
|
||||
pushError(id);
|
||||
setTimeout(() => {
|
||||
handleError(id, callback);
|
||||
}, duration * length);
|
||||
} else {
|
||||
pushError(id);
|
||||
handleError(id, callback);
|
||||
}
|
||||
}
|
||||
|
||||
return handleContinuousError;
|
||||
}
|
Reference in New Issue
Block a user