Skip to content

Commit

Permalink
feat(projects): support repeated request errors occur once in a short…
Browse files Browse the repository at this point in the history
… time. close #368, close #369
  • Loading branch information
honghuangdc committed Apr 26, 2024
1 parent 42f950f commit e3bd397
Show file tree
Hide file tree
Showing 7 changed files with 90 additions and 12 deletions.
6 changes: 6 additions & 0 deletions src/locales/langs/en-us.ts
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,12 @@ const local: App.I18n.Schema = {
superAdminVisible: 'Super Admin Visible',
adminVisible: 'Admin Visible',
adminOrUserVisible: 'Admin and User Visible'
},
request: {
repeatedErrorOccurOnce: 'Repeated Request Error Occurs Once',
repeatedError: 'Repeated Request Error',
repeatedErrorMsg1: 'Custom Request Error 1',
repeatedErrorMsg2: 'Custom Request Error 2'
}
},
manage: {
Expand Down
6 changes: 6 additions & 0 deletions src/locales/langs/zh-cn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,12 @@ const local: App.I18n.Schema = {
superAdminVisible: '超级管理员可见',
adminVisible: '管理员可见',
adminOrUserVisible: '管理员和用户可见'
},
request: {
repeatedErrorOccurOnce: '重复请求错误只出现一次',
repeatedError: '重复请求错误',
repeatedErrorMsg1: '自定义请求错误 1',
repeatedErrorMsg2: '自定义请求错误 2'
}
},
manage: {
Expand Down
24 changes: 12 additions & 12 deletions src/service/request/index.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,16 @@
import type { AxiosResponse } from 'axios';
import { BACKEND_ERROR_CODE, createFlatRequest, createRequest } from '@sa/axios';
import { useAuthStore } from '@/store/modules/auth';
import { $t } from '@/locales';
import { localStg } from '@/utils/storage';
import { getServiceBaseURL } from '@/utils/service';
import { $t } from '@/locales';
import { handleRefreshToken } from './shared';
import { handleRefreshToken, showErrorMsg } from './shared';
import type { RequestInstanceState } from './type';

const isHttpProxy = import.meta.env.DEV && import.meta.env.VITE_HTTP_PROXY === 'Y';
const { baseURL, otherBaseURL } = getServiceBaseURL(import.meta.env, isHttpProxy);

interface InstanceState {
/** whether the request is refreshing token */
isRefreshingToken: boolean;
}

export const request = createFlatRequest<App.Service.Response, InstanceState>(
export const request = createFlatRequest<App.Service.Response, RequestInstanceState>(
{
baseURL,
headers: {
Expand All @@ -35,7 +31,7 @@ export const request = createFlatRequest<App.Service.Response, InstanceState>(
isBackendSuccess(response) {
// when the backend response code is "0000"(default), it means the request is success
// to change this logic by yourself, you can modify the `VITE_SERVICE_SUCCESS_CODE` in `.env` file
return response.data.code === import.meta.env.VITE_SERVICE_SUCCESS_CODE;
return String(response.data.code) === import.meta.env.VITE_SERVICE_SUCCESS_CODE;
},
async onBackendFail(response, instance) {
const authStore = useAuthStore();
Expand All @@ -47,6 +43,8 @@ export const request = createFlatRequest<App.Service.Response, InstanceState>(
function logoutAndCleanup() {
handleLogout();
window.removeEventListener('beforeunload', handleLogout);

request.state.errMsgStack = request.state.errMsgStack.filter(msg => msg !== response.data.msg);
}

// when the backend response code is in `logoutCodes`, it means the user will be logged out and redirected to login page
Expand All @@ -58,13 +56,15 @@ export const request = createFlatRequest<App.Service.Response, InstanceState>(

// when the backend response code is in `modalLogoutCodes`, it means the user will be logged out by displaying a modal
const modalLogoutCodes = import.meta.env.VITE_SERVICE_MODAL_LOGOUT_CODES?.split(',') || [];
if (modalLogoutCodes.includes(response.data.code)) {
if (modalLogoutCodes.includes(response.data.code) && !request.state.errMsgStack?.includes(response.data.msg)) {
request.state.errMsgStack = [...(request.state.errMsgStack || []), response.data.msg];

// prevent the user from refreshing the page
window.addEventListener('beforeunload', handleLogout);

window.$dialog?.error({
title: 'Error',
content: response.data.msg,
content: response.data.code,
positiveText: $t('common.confirm'),
maskClosable: false,
onPositiveClick() {
Expand Down Expand Up @@ -122,7 +122,7 @@ export const request = createFlatRequest<App.Service.Response, InstanceState>(
return;
}

window.$message?.error?.(message);
showErrorMsg(request.state, message);
}
}
);
Expand Down
23 changes: 23 additions & 0 deletions src/service/request/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { AxiosRequestConfig } from 'axios';
import { useAuthStore } from '@/store/modules/auth';
import { localStg } from '@/utils/storage';
import { fetchRefreshToken } from '../api';
import type { RequestInstanceState } from './type';

/**
* refresh token
Expand Down Expand Up @@ -29,3 +30,25 @@ export async function handleRefreshToken(axiosConfig: AxiosRequestConfig) {

return null;
}

export function showErrorMsg(state: RequestInstanceState, message: string) {
if (!state.errMsgStack?.length) {
state.errMsgStack = [];
}

const isExist = state.errMsgStack.includes(message);

if (!isExist) {
state.errMsgStack.push(message);

window.$message?.error(message, {
onLeave: () => {
state.errMsgStack = state.errMsgStack.filter(msg => msg !== message);

setTimeout(() => {
state.errMsgStack = [];
}, 5000);
}
});
}
}
6 changes: 6 additions & 0 deletions src/service/request/type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export interface RequestInstanceState {
/** whether the request is refreshing token */
isRefreshingToken: boolean;
/** the request error message stack */
errMsgStack: string[];
}
6 changes: 6 additions & 0 deletions src/typings/app.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,12 @@ declare namespace App {
adminVisible: string;
adminOrUserVisible: string;
};
request: {
repeatedErrorOccurOnce: string;
repeatedError: string;
repeatedErrorMsg1: string;
repeatedErrorMsg2: string;
};
};
manage: {
common: {
Expand Down
31 changes: 31 additions & 0 deletions src/views/function/request/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,25 @@ async function logoutWithModal() {
async function refreshToken() {
await fetchCustomBackendError('9999', $t('request.tokenExpired'));
}
async function handleRepeatedMessageError() {
await Promise.all([
fetchCustomBackendError('2222', $t('page.function.request.repeatedErrorMsg1')),
fetchCustomBackendError('2222', $t('page.function.request.repeatedErrorMsg1')),
fetchCustomBackendError('2222', $t('page.function.request.repeatedErrorMsg1')),
fetchCustomBackendError('3333', $t('page.function.request.repeatedErrorMsg2')),
fetchCustomBackendError('3333', $t('page.function.request.repeatedErrorMsg2')),
fetchCustomBackendError('3333', $t('page.function.request.repeatedErrorMsg2'))
]);
}
async function handleRepeatedModalError() {
await Promise.all([
fetchCustomBackendError('7777', $t('request.logoutWithModalMsg')),
fetchCustomBackendError('7777', $t('request.logoutWithModalMsg')),
fetchCustomBackendError('7777', $t('request.logoutWithModalMsg'))
]);
}
</script>

<template>
Expand All @@ -26,6 +45,18 @@ async function refreshToken() {
<NCard :title="$t('request.refreshToken')" :bordered="false" size="small" segmented class="card-wrapper">
<NButton @click="refreshToken">{{ $t('common.trigger') }}</NButton>
</NCard>
<NCard
:title="$t('page.function.request.repeatedErrorOccurOnce')"
:bordered="false"
size="small"
segmented
class="card-wrapper"
>
<NButton @click="handleRepeatedMessageError">{{ $t('page.function.request.repeatedError') }}(Message)</NButton>
<NButton class="ml-12px" @click="handleRepeatedModalError">
{{ $t('page.function.request.repeatedError') }}(Modal)
</NButton>
</NCard>
</NSpace>
</template>

Expand Down

0 comments on commit e3bd397

Please sign in to comment.