From 40c5e6d67a2da47e71136e9c3a860222cda002f8 Mon Sep 17 00:00:00 2001 From: NFish Date: Tue, 12 Nov 2024 15:18:19 +0800 Subject: [PATCH] fix: Page may lock if user close the page when refresh access_token (#10550) --- web/service/refresh-token.ts | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/web/service/refresh-token.ts b/web/service/refresh-token.ts index 8bd2215041..b193779629 100644 --- a/web/service/refresh-token.ts +++ b/web/service/refresh-token.ts @@ -1,11 +1,13 @@ import { apiPrefix } from '@/config' import { fetchWithRetry } from '@/utils' +const LOCAL_STORAGE_KEY = 'is_other_tab_refreshing' + let isRefreshing = false function waitUntilTokenRefreshed() { return new Promise((resolve, reject) => { function _check() { - const isRefreshingSign = localStorage.getItem('is_refreshing') + const isRefreshingSign = globalThis.localStorage.getItem(LOCAL_STORAGE_KEY) if ((isRefreshingSign && isRefreshingSign === '1') || isRefreshing) { setTimeout(() => { _check() @@ -22,13 +24,14 @@ function waitUntilTokenRefreshed() { // only one request can send async function getNewAccessToken(): Promise { try { - const isRefreshingSign = localStorage.getItem('is_refreshing') + const isRefreshingSign = globalThis.localStorage.getItem(LOCAL_STORAGE_KEY) if ((isRefreshingSign && isRefreshingSign === '1') || isRefreshing) { await waitUntilTokenRefreshed() } else { - globalThis.localStorage.setItem('is_refreshing', '1') isRefreshing = true + globalThis.localStorage.setItem(LOCAL_STORAGE_KEY, '1') + globalThis.addEventListener('beforeunload', releaseRefreshLock) const refresh_token = globalThis.localStorage.getItem('refresh_token') // Do not use baseFetch to refresh tokens. @@ -61,15 +64,21 @@ async function getNewAccessToken(): Promise { return Promise.reject(error) } finally { + releaseRefreshLock() + } +} + +function releaseRefreshLock() { + if (isRefreshing) { isRefreshing = false - globalThis.localStorage.removeItem('is_refreshing') + globalThis.localStorage.removeItem(LOCAL_STORAGE_KEY) + globalThis.removeEventListener('beforeunload', releaseRefreshLock) } } export async function refreshAccessTokenOrRelogin(timeout: number) { return Promise.race([new Promise((resolve, reject) => setTimeout(() => { - isRefreshing = false - globalThis.localStorage.removeItem('is_refreshing') + releaseRefreshLock() reject(new Error('request timeout')) }, timeout)), getNewAccessToken()]) }