@shencom/request
Version:
封装 axios 请求,兼容了 uni-app 的 uni.request 和 uni.uploadFile 的适配器
153 lines (123 loc) • 4.39 kB
text/typescript
import type { AxiosAdapter, AxiosRequestConfig } from 'axios';
import axios from 'axios';
// @ts-expect-error 没有声明文件
import settle from 'axios/unsafe/core/settle.js';
type GeneralCallbackResultCustom = UniApp.GeneralCallbackResult & {
data?: unknown;
statusCode?: number;
header?: unknown;
};
function isFileType(files: any[]) {
return files.some((file) => file.name && file.file);
}
function isMultiUpload(config: Record<string, any>) {
return Array.isArray(config.files) && config.files.length > 0;
}
const isObject = (data: any) => Object.prototype.toString.call(data) === '[object Object]';
const isAliFormData = (data: any) =>
isObject(data) && 'appendData' in data && 'realFormData' in data;
const isFormData = (data: unknown): data is FormData =>
Object.prototype.toString.call(data) === '[object FormData]' || isAliFormData(data);
function isUploadFile(config: Record<string, any>) {
if (isFormData(config.data)) return true;
if (config.method === 'post') {
if (config.data) {
const data = JSON.parse(config.data);
if (data.file?.path) return true;
if (data.filePath) return true;
if (isMultiUpload(data) && isFileType(data.files)) return true;
}
}
return false;
}
interface Config extends AxiosRequestConfig {
formData?: FormData;
header?: AxiosRequestConfig['headers'];
complete?: (response: UniApp.RequestSuccessCallbackResult & UniApp.GeneralCallbackResult) => void;
}
function format(config: Config, resolve: (value: unknown) => void, reject: (reason?: any) => void) {
const uniConfig = {
...config,
url: axios.getUri(config),
header: { ...config.headers },
} as Config & UniApp.UploadFileOption;
delete uniConfig.headers;
if (isUploadFile(uniConfig)) {
delete uniConfig.header?.['Content-Type']; // Let the browser set it
if (typeof uniConfig.data === 'string') {
const data = JSON.parse(uniConfig.data);
uniConfig.formData = {};
Object.keys(data).forEach((name) => {
const value = data[name];
if (name === 'file') {
uniConfig.filePath = value?.path;
return;
}
if (name === 'filePath') uniConfig.filePath = value as string;
uniConfig.formData[name] = value;
});
uniConfig.name = 'file';
delete uniConfig.data;
}
} else if (uniConfig.method?.toLocaleUpperCase() === 'GET') {
// 兼容 get 时的 params 字段
uniConfig.data = uniConfig.data ? uniConfig.data : uniConfig.params;
}
uniConfig.complete = function (response: GeneralCallbackResultCustom) {
const result = {
data: response.data,
status: response.statusCode,
statusText: response.errMsg,
headers: response.header,
config: uniConfig,
};
settle(resolve, reject, result);
};
return uniConfig;
}
function uniappAdapter(config: AxiosRequestConfig = {}) {
return new Promise((resolve, reject) => {
const uniConfig = format(config, resolve, reject);
let requestTask: UniApp.RequestTask | null;
if (config.cancelToken) {
config.cancelToken.promise.then((cancel) => {
if (!requestTask) return;
requestTask.abort();
reject(cancel);
// 取消请求
requestTask = null;
});
}
if (isUploadFile(config)) {
if (typeof FormData === 'undefined') {
requestTask = uni.uploadFile(uniConfig) as unknown as UniApp.RequestTask;
} else {
// uniapp H5 环境下,使用 uni.uploadFile 发送请求,不返回响应头
// 需要使用 axios 发送请求
const controller = new AbortController();
delete uniConfig.header;
axios
.request({
...uniConfig,
headers: config.headers,
signal: controller.signal,
// @ts-expect-error uniapp 的 H5 环境下需要移除适配器
adapter: null,
})
.then((res) => {
settle(resolve, reject, res);
})
.catch((err) => {
settle(resolve, reject, err);
});
requestTask = controller as unknown as UniApp.UploadTask;
}
} else {
requestTask = uni.request(
uniConfig as UniApp.RequestOptions,
) as unknown as UniApp.RequestTask;
}
});
}
const adapter = uniappAdapter as AxiosAdapter;
export { adapter };