vben请求接口格式
(代码提取主要的,有删减)
enum Api {
AccountList = '/system/getAccountList',
IsAccountExist = '/system/accountExist',
DeptList = '/system/getDeptList',
setRoleStatus = '/system/setRoleStatus',
MenuList = '/system/getMenuList',
RolePageList = '/system/getRoleListByPage',
GetAllRoleList = '/system/getAllRoleList',
}
export const getAccountList = (params: AccountParams) =>
//AccountListGetResultModel为params的type类型
defHttp.get<AccountListGetResultModel>({ url: Api.AccountList, params });
请求接口时通过defHttp变量的get方法
defHttp传入配置
export const defHttp = createAxios();
function createAxios(opt?: Partial<CreateAxiosOptions>) {
return new VAxios(
deepMerge(
{
// See https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication#authentication_schemes
// authentication schemes,e.g: Bearer
// authenticationScheme: 'Bearer',
authenticationScheme: '',
timeout: 10 * 1000,
// 基础接口地址
// baseURL: globSetting.apiUrl,
headers: { 'Content-Type': ContentTypeEnum.JSON },
// 如果是form-data格式
// headers: { 'Content-Type': ContentTypeEnum.FORM_URLENCODED },
// 数据处理方式
transform,
// 配置项,下面的选项都可以在独立的接口请求中覆盖
requestOptions: {
// 默认将prefix 添加到url
joinPrefix: true,
// 是否返回原生响应头 比如:需要获取响应头时使用该属性
isReturnNativeResponse: false,
// 需要对返回数据进行处理
isTransformResponse: true,
// post请求的时候添加参数到url
joinParamsToUrl: false,
// 格式化提交参数时间
formatDate: true,
// 消息提示类型
errorMessageMode: 'message',
// 接口地址
apiUrl: globSetting.apiUrl,
// 接口拼接地址
urlPrefix: urlPrefix,
// 是否加入时间戳
joinTime: true,
// 忽略重复请求
ignoreCancelToken: true,
// 是否携带token
withToken: true,
},
},
opt || {},
),
);
}
该变量是实例化了VAxios,
transform
import type { AxiosRequestConfig, AxiosResponse } from 'axios';
import type { RequestOptions, Result } from 'types/axios';
export interface CreateAxiosOptions extends AxiosRequestConfig {
authenticationScheme?: string; //代表什么?
transform?: AxiosTransform; // 数据处理类
requestOptions?: RequestOptions; // 请求数据
}
/**
* 抽象类 数据处理类
*/
export abstract class AxiosTransform {
// ? 请求直接拦截器函数 入参为请求参数和自定义请求参数
requestInterceptors?: (config: AxiosRequestConfig, options: CreateAxiosOptions) => AxiosRequestConfig;
// ? 请求拦截器错误处理
requestInterceptorsCatch?: (error: Error) => void;
// ? 处理请求之前的options参数的 加工函数
beforeRequestHook?: (config: AxiosRequestConfig, options: RequestOptions) => AxiosRequestConfig;
// ? 处理请求失败的 加工函数
requestCatchHook?: (e: Error, options: RequestOptions) => Promise<any>;
// * 响应拦截器
responseInterceptors?: (res: AxiosResponse<any>) => AxiosResponse<any>;
// * 处理成功返回参数的 加工函数
transformRequestHook?: (res: AxiosResponse<Result>, options:RequestOptions) => any;
// * 响应拦截器错误处理
responseInterceptorsCatch?: (error: Error) => void;
}
VAxios
请求接口时会触发request方法,具体内容如下
而transform解构了三个方法分别是: 请求之前处理config:beforeRequestHook,返回数据有误时:requestCatchHook, 请求之后处理数据:transformRequestHook
beforeRequestHook
beforeRequestHook: (config, options) => {
//apiUrl='/basic-api'为统一的请求
//VITE_GLOB_API_URL=/basic-api
const { apiUrl, joinPrefix, joinParamsToUrl, formatDate, joinTime = true, urlPrefix } = options;
//拼接url
if (apiUrl && isString(apiUrl)) {
config.url = `${apiUrl}${config.url}`;
// config.url='basic-api/getUserInfo'
}
const params = config.params || {};
const data = config.data || false;
formatDate && data && !isString(data) && formatRequestDate(data);
if (config.method?.toUpperCase() === RequestEnum.GET) {
if (!isString(params)) {
// 给 get 请求加上时间戳参数,避免从缓存中拿数据。
config.params = Object.assign(params || {}, joinTimestamp(joinTime, false));
} else {
// 兼容restful风格
config.url = config.url + params + `${joinTimestamp(joinTime, true)}`;
config.params = undefined;
}
} else {
if (!isString(params)) {
formatDate && formatRequestDate(params);
if (Reflect.has(config, 'data') && config.data && Object.keys(config.data).length > 0) {
config.data = data;
config.params = params;
} else {
// 非GET请求如果没有提供data,则将params视为data
config.data = params;
config.params = undefined;
}
if (joinParamsToUrl) {
config.url = setObjToUrlParams(
config.url as string,
Object.assign({}, config.params, config.data),
);
}
} else {
// 兼容restful风格
config.url = config.url + params;
config.params = undefined;
}
}
return config;
},
然后会触发请求拦截器
requestInterceptors
requestInterceptors: (config, options) => {
// 请求之前处理config
debugger;
const token = getToken();
if (token && (config as Recordable)?.requestOptions?.withToken !== false) {
// jwt token
(config as Recordable).headers.Authorization = options.authenticationScheme
? `${options.authenticationScheme} ${token}`
: token;
}
return config;
},
获取数据只有就需执行响应拦截器进行处理
responseInterceptors
responseInterceptors: (res: AxiosResponse<any>) => {
return res;
},
响应拦截器后需要对会返回数据进行处理
transformRequestHook
transformRequestHook: (res: AxiosResponse<Result>, options: RequestOptions) => {
debugger;
const { t } = useI18n();
const { isTransformResponse, isReturnNativeResponse } = options;
// 是否返回原生响应头 比如:需要获取响应头时使用该属性
if (isReturnNativeResponse) {
return res;
}
// 不进行任何处理,直接返回
// 用于页面代码可能需要直接获取code,data,message这些信息时开启
if (!isTransformResponse) {
return res.data;
}
// 错误的时候返回
const { data } = res;
if (!data) {
// return '[HTTP] Request has no return value';
throw new Error(t('sys.api.apiRequestFailed'));
}
// 这里 code,result,message为 后台统一的字段,需要在 types.ts内修改为项目自己的接口返回格式
const { code, result, message } = data;
// 这里逻辑可以根据项目进行修改
const hasSuccess = data && Reflect.has(data, 'code') && code === ResultEnum.SUCCESS;
if (hasSuccess) {
return result;
}
// 在此处根据自己项目的实际情况对不同的code执行不同的操作
// 如果不希望中断当前请求,请return数据,否则直接抛出异常即可
let timeoutMsg = '';
switch (code) {
case ResultEnum.TIMEOUT:
timeoutMsg = t('sys.api.timeoutMessage');
const userStore = useUserStoreWithOut();
userStore.setToken(undefined);
userStore.logout(true);
break;
default:
if (message) {
timeoutMsg = message;
}
}
// errorMessageMode=‘modal’的时候会显示modal错误弹窗,而不是消息提示,用于一些比较重要的错误
// errorMessageMode='none' 一般是调用时明确表示不希望自动弹出错误提示
if (options.errorMessageMode === 'modal') {
createErrorModal({ title: t('sys.api.errorTip'), content: timeoutMsg });
} else if (options.errorMessageMode === 'message') {
createMessage.error(timeoutMsg);
}
throw new Error(timeoutMsg || t('sys.api.apiRequestFailed'));
},
此为请求接口到获取数据的流程,以及一些拦截器的具体实现。
总结:
生成defHttp对象时,new一个class类VAxios,其中传入参数进行配置,并且其中的get和post等请求中统一调用request方法,届时通过引入transform的具体请求拦截、响应拦截成功、响应失败处理、数据转化等方法实现不同接口的自定义要求。