1. 依赖安装
pnpm install axios -S
2. 直接上代码
1. axios.ts
import { CancelTokenItem, HttpAxiosConfig, HttpResponseData } from '@/domain/axios';
import axios, { AxiosError, AxiosInstance, AxiosResponse, InternalAxiosRequestConfig } from 'axios';
import { sleep } from '@/utils';
export class HttpAxios {
instance: AxiosInstance;
method: string = 'post';
timeout: number = 300 * 1000;
loadingInstance: any = null;
requestCount: number = 0;
cancelTokenArr: CancelTokenItem[] = [];
clearFlag = true;
constructor(config: HttpAxiosConfig = {}) {
let instance = axios.create(config);
instance.interceptors.request.use(
(config: InternalAxiosRequestConfig) => this.onBeforeRequest(config),
(config: InternalAxiosRequestConfig) => this.onRequestRejected(config)
);
instance.interceptors.response.use(
(response: any) => this.onResponseResolved(response),
(error: any) => this.onResponseRejected(error)
);
this.instance = instance;
}
private showLoading(config: HttpAxiosConfig) {
if (config.showLoading && !this.loadingInstance) {
}
this.requestCount++;
}
private hideLoading() {
this.requestCount--;
if (this.requestCount === 0 && this.loadingInstance) {
this.loadingInstance = null;
}
}
onBeforeRequest = (config: InternalAxiosRequestConfig): InternalAxiosRequestConfig => {
this.showLoading(config);
let _config = {
withCredentials: false,
timeout: this.timeout,
};
if (this.method == 'formate') {
config.headers.setContentType('application/x-www-form-urlencoded; charset=UTF-8');
}
config.cancelToken = new axios.CancelToken((cancel) => {
this.cancelTokenArr.push({ cancel, url: config.url || '' });
});
return Object.assign({}, config, _config);
};
onRequestRejected = (error: any): Promise<any> => {
return Promise.reject(error);
};
onResponseResolved = async (response: AxiosResponse) => {
let responseData: HttpResponseData<any> = response.data || {};
const { code, data } = responseData;
if (code === 200) {
return data || '';
}
await this.retryRequest(response.config);
this.hideLoading();
return undefined;
};
retryRequest = async (config: HttpAxiosConfig) => {
config.retryCount = config.retryCount ?? 0;
if (config && config.maxRetries && config.retryCount < config.maxRetries) {
config.retryCount = config.retryCount + 1;
await sleep(config.retryDelay || 1000);
return this.instance(config);
}
};
onResponseRejected = async (error: AxiosError) => {
const { config = {}, message } = error;
await this.retryRequest(config ?? {});
if (this.loadingInstance) {
this.loadingInstance.close();
this.loadingInstance = null;
}
this.hideLoading();
if (/timeout/g.test(message)) {
return Promise.reject(error);
}
return Promise.reject(error);
};
sendRequest = (url: string, params: Record<string, any> = {}, method: string = 'post', config: HttpAxiosConfig = {}) => {
if (!this.instance) {
return;
}
this.method = method;
if (config?.maxRetries) {
config.retryCount = 0;
}
const _method = method.toLocaleLowerCase();
if (_method === 'get') {
params = {
params: params,
};
return this.instance.get(url, { ...params, ...config });
}
if (_method === 'formdata') {
let reqData = new FormData();
for (let key in params) {
reqData.append(key, params[key]);
}
return this.instance.post(url, reqData, config);
}
return this.instance.post(url, params, config);
};
async cancelRequest(url: string) {
if (this.cancelTokenArr.length === 0) {
return;
}
for (let i = 0; i < this.cancelTokenArr.length; i++) {
if (this.cancelTokenArr[i].url === url) {
this.cancelTokenArr[i].cancel();
this.cancelTokenArr.splice(i, 1);
break;
}
}
}
async clearRequests() {
if (this.cancelTokenArr.length === 0 || !this.clearFlag) {
return;
}
this.cancelTokenArr.forEach((ele) => {
ele.cancel();
});
this.cancelTokenArr = [];
}
}
export const getHttpAxiosInstance = () => {
let instance: HttpAxios | null = null;
return () => {
if (!instance) {
instance = new HttpAxios({});
}
return instance;
};
};
2. 生成axios instance,并将api Maps转换为对应的请求函数
import { AxiosSendRequestParam, HttpAxiosConfig } from '@/domain/axios';
import { getHttpAxiosInstance, HttpAxios } from './axios';
import demo from './demo';
const httpAxios: HttpAxios = getHttpAxiosInstance()();
const maps2Method = (apiMaps: Record<string, AxiosSendRequestParam>) => {
let result: Record<string, any> = {};
for (let key in apiMaps) {
const { method, url, params, config } = apiMaps[key];
result[key] = (_params: Record<string, any>, _config: HttpAxiosConfig) => {
return httpAxios.sendRequest(url, { ...params, ..._params }, method, { ...config, ..._config });
};
}
return result;
};
export default {
...maps2Method({
...demo,
}),
};
3. 用到的axios中相关模型
import { AxiosHeaders, AxiosRequestConfig, Canceler, Method } from 'axios';
export interface HttpAxiosConfig extends AxiosRequestConfig {
showLoading?: boolean;
noAuth?: boolean;
maxRetries?: number;
retryDelay?: number;
retryCount?: number;
}
export interface AxiosSendRequestParam {
method: Method;
url: string;
params?: Record<string, any>;
headers?: AxiosHeaders;
config?: HttpAxiosConfig;
}
export interface ApiMaps {
[propName: string]: AxiosSendRequestParam;
}
export type CancelTokenItem = {
cancel: Canceler;
url: string;
};
export interface HttpResponseData<T> {
code: number;
data: T;
message: string;
}
4. demo.ts
import { AxiosSendRequestParam } from "@/domain/axios"
const demo: Record<string, AxiosSendRequestParam> = {
demo: {
method: 'post',
url: '/api/demo',
}
}
export default demo;
5. 在vue中使用
<script setup lang="ts">
import api from '@/api';
const request = async (): Promise<void> => {
const res = await api.demo();
console.log(res);
}
request();
</script>