mirror of
https://github.com/vbenjs/gf-vben-admin.git
synced 2025-01-23 11:50:20 +08:00
feat: add request retry (#1553)
This commit is contained in:
parent
78535bdd86
commit
136cbb1e3b
@ -111,4 +111,12 @@ export default [
|
|||||||
return resultSuccess(undefined, { message: 'Token has been destroyed' });
|
return resultSuccess(undefined, { message: 'Token has been destroyed' });
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
url: '/basic-api/testRetry',
|
||||||
|
statusCode: 405,
|
||||||
|
method: 'get',
|
||||||
|
response: () => {
|
||||||
|
return resultError('Error!');
|
||||||
|
},
|
||||||
|
},
|
||||||
] as MockMethod[];
|
] as MockMethod[];
|
||||||
|
@ -8,6 +8,7 @@ enum Api {
|
|||||||
Logout = '/logout',
|
Logout = '/logout',
|
||||||
GetUserInfo = '/getUserInfo',
|
GetUserInfo = '/getUserInfo',
|
||||||
GetPermCode = '/getPermCode',
|
GetPermCode = '/getPermCode',
|
||||||
|
TestRetry = '/testRetry',
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -39,3 +40,16 @@ export function getPermCode() {
|
|||||||
export function doLogout() {
|
export function doLogout() {
|
||||||
return defHttp.get({ url: Api.Logout });
|
return defHttp.get({ url: Api.Logout });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function testRetry() {
|
||||||
|
return defHttp.get(
|
||||||
|
{ url: Api.TestRetry },
|
||||||
|
{
|
||||||
|
retryRequest: {
|
||||||
|
isOpenRetry: true,
|
||||||
|
count: 5,
|
||||||
|
waitTime: 1000,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@ -92,6 +92,7 @@ export default {
|
|||||||
breadcrumb: 'Breadcrumbs',
|
breadcrumb: 'Breadcrumbs',
|
||||||
breadcrumbFlat: 'Flat Mode',
|
breadcrumbFlat: 'Flat Mode',
|
||||||
breadcrumbFlatDetail: 'Flat mode details',
|
breadcrumbFlatDetail: 'Flat mode details',
|
||||||
|
requestDemo: 'Retry request demo',
|
||||||
|
|
||||||
breadcrumbChildren: 'Level mode',
|
breadcrumbChildren: 'Level mode',
|
||||||
breadcrumbChildrenDetail: 'Level mode detail',
|
breadcrumbChildrenDetail: 'Level mode detail',
|
||||||
|
@ -88,6 +88,7 @@ export default {
|
|||||||
ws: 'websocket测试',
|
ws: 'websocket测试',
|
||||||
breadcrumb: '面包屑导航',
|
breadcrumb: '面包屑导航',
|
||||||
breadcrumbFlat: '平级模式',
|
breadcrumbFlat: '平级模式',
|
||||||
|
requestDemo: '测试请求重试',
|
||||||
breadcrumbFlatDetail: '平级详情',
|
breadcrumbFlatDetail: '平级详情',
|
||||||
breadcrumbChildren: '层级模式',
|
breadcrumbChildren: '层级模式',
|
||||||
breadcrumbChildrenDetail: '层级详情',
|
breadcrumbChildrenDetail: '层级详情',
|
||||||
|
@ -31,6 +31,15 @@ const feat: AppRouteModule = {
|
|||||||
title: t('routes.demo.feat.ws'),
|
title: t('routes.demo.feat.ws'),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'request',
|
||||||
|
name: 'RequestDemo',
|
||||||
|
// @ts-ignore
|
||||||
|
component: () => import('/@/views/demo/feat/request-demo/index.vue'),
|
||||||
|
meta: {
|
||||||
|
title: t('routes.demo.feat.requestDemo'),
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: 'session-timeout',
|
path: 'session-timeout',
|
||||||
name: 'SessionTimeout',
|
name: 'SessionTimeout',
|
||||||
|
@ -111,7 +111,10 @@ export class VAxios {
|
|||||||
// Response result interceptor error capture
|
// Response result interceptor error capture
|
||||||
responseInterceptorsCatch &&
|
responseInterceptorsCatch &&
|
||||||
isFunction(responseInterceptorsCatch) &&
|
isFunction(responseInterceptorsCatch) &&
|
||||||
this.axiosInstance.interceptors.response.use(undefined, responseInterceptorsCatch);
|
this.axiosInstance.interceptors.response.use(undefined, (error) => {
|
||||||
|
// @ts-ignore
|
||||||
|
responseInterceptorsCatch(this.axiosInstance, error);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
28
src/utils/http/axios/axiosRetry.ts
Normal file
28
src/utils/http/axios/axiosRetry.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import { AxiosError, AxiosInstance } from 'axios';
|
||||||
|
/**
|
||||||
|
* 请求重试机制
|
||||||
|
*/
|
||||||
|
|
||||||
|
export class AxiosRetry {
|
||||||
|
/**
|
||||||
|
* 重试
|
||||||
|
*/
|
||||||
|
retry(AxiosInstance: AxiosInstance, error: AxiosError) {
|
||||||
|
// @ts-ignore
|
||||||
|
const { config } = error.response;
|
||||||
|
const { waitTime, count } = config?.requestOptions?.retryRequest;
|
||||||
|
config.__retryCount = config.__retryCount || 0;
|
||||||
|
if (config.__retryCount >= count) {
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
|
config.__retryCount += 1;
|
||||||
|
return this.delay(waitTime).then(() => AxiosInstance(config));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 延迟
|
||||||
|
*/
|
||||||
|
private delay(waitTime: number) {
|
||||||
|
return new Promise((resolve) => setTimeout(resolve, waitTime));
|
||||||
|
}
|
||||||
|
}
|
@ -48,5 +48,5 @@ export abstract class AxiosTransform {
|
|||||||
/**
|
/**
|
||||||
* @description: 请求之后的拦截器错误处理
|
* @description: 请求之后的拦截器错误处理
|
||||||
*/
|
*/
|
||||||
responseInterceptorsCatch?: (error: Error) => void;
|
responseInterceptorsCatch?: (axiosInstance: AxiosResponse, error: Error) => void;
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ import { useErrorLogStoreWithOut } from '/@/store/modules/errorLog';
|
|||||||
import { useI18n } from '/@/hooks/web/useI18n';
|
import { useI18n } from '/@/hooks/web/useI18n';
|
||||||
import { joinTimestamp, formatRequestDate } from './helper';
|
import { joinTimestamp, formatRequestDate } from './helper';
|
||||||
import { useUserStoreWithOut } from '/@/store/modules/user';
|
import { useUserStoreWithOut } from '/@/store/modules/user';
|
||||||
|
import { AxiosRetry } from '/@/utils/http/axios/axiosRetry';
|
||||||
|
|
||||||
const globSetting = useGlobSetting();
|
const globSetting = useGlobSetting();
|
||||||
const urlPrefix = globSetting.urlPrefix;
|
const urlPrefix = globSetting.urlPrefix;
|
||||||
@ -158,7 +159,7 @@ const transform: AxiosTransform = {
|
|||||||
/**
|
/**
|
||||||
* @description: 响应错误处理
|
* @description: 响应错误处理
|
||||||
*/
|
*/
|
||||||
responseInterceptorsCatch: (error: any) => {
|
responseInterceptorsCatch: (axiosInstance: AxiosResponse, error: any) => {
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const errorLogStore = useErrorLogStoreWithOut();
|
const errorLogStore = useErrorLogStoreWithOut();
|
||||||
errorLogStore.addAjaxErrorInfo(error);
|
errorLogStore.addAjaxErrorInfo(error);
|
||||||
@ -189,6 +190,14 @@ const transform: AxiosTransform = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
checkStatus(error?.response?.status, msg, errorMessageMode);
|
checkStatus(error?.response?.status, msg, errorMessageMode);
|
||||||
|
|
||||||
|
// 添加自动重试机制 保险起见 只针对GET请求
|
||||||
|
const retryRequest = new AxiosRetry();
|
||||||
|
const { isOpenRetry } = config.requestOptions.retryRequest;
|
||||||
|
config.method?.toUpperCase() === RequestEnum.GET &&
|
||||||
|
isOpenRetry &&
|
||||||
|
// @ts-ignore
|
||||||
|
retryRequest.retry(axiosInstance, error);
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -234,6 +243,11 @@ function createAxios(opt?: Partial<CreateAxiosOptions>) {
|
|||||||
ignoreCancelToken: true,
|
ignoreCancelToken: true,
|
||||||
// 是否携带token
|
// 是否携带token
|
||||||
withToken: true,
|
withToken: true,
|
||||||
|
retryRequest: {
|
||||||
|
isOpenRetry: true,
|
||||||
|
count: 5,
|
||||||
|
waitTime: 100,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
opt || {},
|
opt || {},
|
||||||
|
23
src/views/demo/feat/request-demo/index.vue
Normal file
23
src/views/demo/feat/request-demo/index.vue
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<template>
|
||||||
|
<div class="request-box">
|
||||||
|
<a-button @click="handleClick" color="primary"> 点击会重新发起请求5次 </a-button>
|
||||||
|
<p>打开浏览器的network面板,可以看到发出了六次请求</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { testRetry } from '/@/api/sys/user';
|
||||||
|
// @ts-ignore
|
||||||
|
const handleClick = async () => {
|
||||||
|
await testRetry();
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
.request-box {
|
||||||
|
margin: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
7
types/axios.d.ts
vendored
7
types/axios.d.ts
vendored
@ -23,8 +23,15 @@ export interface RequestOptions {
|
|||||||
ignoreCancelToken?: boolean;
|
ignoreCancelToken?: boolean;
|
||||||
// Whether to send token in header
|
// Whether to send token in header
|
||||||
withToken?: boolean;
|
withToken?: boolean;
|
||||||
|
// 请求重试机制
|
||||||
|
retryRequest?: RetryRequest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface RetryRequest {
|
||||||
|
isOpenRetry: boolean;
|
||||||
|
count: number;
|
||||||
|
waitTime: number;
|
||||||
|
}
|
||||||
export interface Result<T = any> {
|
export interface Result<T = any> {
|
||||||
code: number;
|
code: number;
|
||||||
type: 'success' | 'error' | 'warning';
|
type: 'success' | 'error' | 'warning';
|
||||||
|
Loading…
Reference in New Issue
Block a user