@shencom/request
Version:
封装 axios 请求,兼容了 uni-app 的 uni.request 和 uni.uploadFile 的适配器
146 lines (120 loc) • 3.94 kB
text/typescript
import type { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
import axios from 'axios';
import { pickBy } from 'lodash-es';
declare module 'axios' {
interface AxiosRequestConfig {
isFilterEmpty?: boolean;
errcode?: string;
}
}
type Dictionary<T = any> = Record<string, T>;
export type Platforms = true | 'weixin' | 'ali' | 'h5' | 'app';
export interface ScHeaders extends Dictionary {
scid: string;
Authorization?: string | null;
miniProgram: Platforms;
}
export interface ScResponse<T> {
data: T;
errcode: string;
errmsg: string;
}
export interface Config<D = Dictionary> extends AxiosRequestConfig<D> {
headers?: Partial<ScHeaders>;
}
export type ScRequest = <R = Dictionary, D = Dictionary, CustomRes = false>(
url: string,
data?: D,
config?: Config<D>,
) => Promise<CustomRes extends true ? R : ScResponse<R>>;
export interface CustomAxiosInstance extends Omit<AxiosInstance, 'post' | 'get'> {
post: ScRequest;
get: ScRequest;
upload: typeof __upload;
}
const instance = axios.create() as unknown as CustomAxiosInstance;
instance.defaults.errcode = '0000';
instance.defaults.isFilterEmpty = true;
instance.defaults.timeout = 20000;
const isObject = (data: any) => Object.prototype.toString.call(data) === '[object Object]';
function handledBodyEmpty(data: any | any[]) {
if (!data) return {};
if (Array.isArray(data)) {
return data.map((item) => {
if (isObject(item)) return pickBy(item, (v) => v !== null && v !== undefined && v !== '');
return item;
});
}
if (isObject(data)) {
return pickBy(data, (v) => v !== '');
}
return data;
}
function checkFilterEmpty(config: AxiosRequestConfig<any | any[]>) {
if (['POST', 'GET'].includes(config.method?.toLocaleUpperCase() || '')) {
config.data = handledBodyEmpty(config.data);
}
if (config.method?.toLocaleUpperCase() === 'GET') {
if (config.params) config.params = handledBodyEmpty(config.params);
}
return config;
}
const __base = <R = Dictionary>(url: string, config: AxiosRequestConfig) => {
let { isFilterEmpty = true } = instance.defaults;
if (typeof config?.isFilterEmpty === 'boolean') {
isFilterEmpty = config.isFilterEmpty;
}
if (isFilterEmpty) config = checkFilterEmpty(config);
const errcode = config?.errcode ?? instance.defaults.errcode;
return new Promise<R>((resolve, reject) => {
instance
.request({ url, ...config })
.then((res) => {
if (res.data.errcode) {
if (res.data?.errcode === errcode) {
resolve(res.data);
return;
}
reject(res);
} else {
resolve(res.data);
}
})
.catch(reject);
});
};
const __post: ScRequest = (url, data, config) => {
return __base(url, { data, ...config, method: 'post' });
};
const __get: ScRequest = (url, data, config) => {
return __base(url, { params: data, ...config, method: 'get' });
};
const __upload = <R = Dictionary, D = Dictionary, CustomRes = false>(
url: string,
data: D,
config?: Config<D>,
): Promise<CustomRes extends true ? AxiosResponse<R, D> : ScResponse<R>> => {
return new Promise((resolve, reject) => {
instance
.request({ url, data, ...config, method: 'post' })
.then((res) => {
if (res.status === 200) {
// oss 直传情况下,返回的是空字符串
if (typeof res.data === 'string' && res.data === '') {
// oss 成功请求后不返回数据
// 需要从 Headers 中获取 Etag 数据,所以不进行数据过滤
resolve(res as any);
} else if (res.data?.errcode === res.config?.errcode) {
resolve(res.data);
} else {
reject(res);
}
} else reject(res);
})
.catch(reject);
});
};
instance.post = __post;
instance.get = __get;
instance.upload = __upload;
export { instance };