Skip to content

Commit

Permalink
fix(projects): fix refresh token when meet multi requests
Browse files Browse the repository at this point in the history
  • Loading branch information
honghuangdc committed Sep 8, 2024
1 parent 4909291 commit 5ae17e6
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 33 deletions.
2 changes: 1 addition & 1 deletion .env
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ VITE_SERVICE_LOGOUT_CODES=8888,8889
VITE_SERVICE_MODAL_LOGOUT_CODES=7777,7778

# token expired codes of backend service, when the code is received, it will refresh the token and resend the request
VITE_SERVICE_EXPIRED_TOKEN_CODES=9999,9998
VITE_SERVICE_EXPIRED_TOKEN_CODES=9999,9998,3333

# when the route mode is static, the defined super role
VITE_STATIC_SUPER_ROLE=R_SUPER
Expand Down
24 changes: 9 additions & 15 deletions src/service/request/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useAuthStore } from '@/store/modules/auth';
import { localStg } from '@/utils/storage';
import { getServiceBaseURL } from '@/utils/service';
import { $t } from '@/locales';
import { handleRefreshToken, showErrorMsg } from './shared';
import { getAuthorization, handleExpiredRequest, showErrorMsg } from './shared';
import type { RequestInstanceState } from './type';

const isHttpProxy = import.meta.env.DEV && import.meta.env.VITE_HTTP_PROXY === 'Y';
Expand All @@ -19,12 +19,8 @@ export const request = createFlatRequest<App.Service.Response, RequestInstanceSt
},
{
async onRequest(config) {
const { headers } = config;

// set token
const token = localStg.get('token');
const Authorization = token ? `Bearer ${token}` : null;
Object.assign(headers, { Authorization });
const Authorization = getAuthorization();
Object.assign(config.headers, { Authorization });

return config;
},
Expand Down Expand Up @@ -82,15 +78,13 @@ export const request = createFlatRequest<App.Service.Response, RequestInstanceSt
// when the backend response code is in `expiredTokenCodes`, it means the token is expired, and refresh token
// the api `refreshToken` can not return error code in `expiredTokenCodes`, otherwise it will be a dead loop, should return `logoutCodes` or `modalLogoutCodes`
const expiredTokenCodes = import.meta.env.VITE_SERVICE_EXPIRED_TOKEN_CODES?.split(',') || [];
if (expiredTokenCodes.includes(responseCode) && !request.state.isRefreshingToken) {
request.state.isRefreshingToken = true;

const refreshConfig = await handleRefreshToken(response.config);

request.state.isRefreshingToken = false;
if (expiredTokenCodes.includes(responseCode)) {
const success = await handleExpiredRequest(request.state);
if (success) {
const Authorization = getAuthorization();
Object.assign(response.config.headers, { Authorization });

if (refreshConfig) {
return instance.request(refreshConfig) as Promise<AxiosResponse>;
return instance.request(response.config) as Promise<AxiosResponse>;
}
}

Expand Down
42 changes: 26 additions & 16 deletions src/service/request/shared.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,44 @@
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
*
* @param axiosConfig - request config when the token is expired
*/
export async function handleRefreshToken(axiosConfig: AxiosRequestConfig) {
export function getAuthorization() {
const token = localStg.get('token');
const Authorization = token ? `Bearer ${token}` : null;

return Authorization;
}

/** refresh token */
async function handleRefreshToken() {
const { resetStore } = useAuthStore();

const refreshToken = localStg.get('refreshToken') || '';
const { error, data } = await fetchRefreshToken(refreshToken);
const rToken = localStg.get('refreshToken') || '';
const { error, data } = await fetchRefreshToken(rToken);
if (!error) {
localStg.set('token', data.token);
localStg.set('refreshToken', data.refreshToken);
return true;
}

const config = { ...axiosConfig };
if (config.headers) {
config.headers.Authorization = data.token;
}
resetStore();

return config;
return false;
}

export async function handleExpiredRequest(state: RequestInstanceState) {
if (!state.refreshTokenFn) {
state.refreshTokenFn = handleRefreshToken();
}

resetStore();
const success = await state.refreshTokenFn;

setTimeout(() => {
state.refreshTokenFn = null;
}, 1000);

return null;
return success;
}

export function showErrorMsg(state: RequestInstanceState, message: string) {
Expand Down
2 changes: 1 addition & 1 deletion src/service/request/type.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export interface RequestInstanceState {
/** whether the request is refreshing token */
isRefreshingToken: boolean;
refreshTokenFn: Promise<boolean> | null;
/** the request error message stack */
errMsgStack: string[];
}

0 comments on commit 5ae17e6

Please sign in to comment.