Creé una clase TokenService con el propósito de devolver un token de acceso. La función getToken verifica si el token ha caducado y, si es verdadero, intentará obtener un nuevo accessToken dado el refreshToken. Sin embargo, es importante que solo salga una solicitud para intentar actualizar el token. Por lo tanto, si la función se llama en paralelo, debe esperar hasta que se complete la primera llamada y devolver ese resultado para todas las demás llamadas.
Esta es mi implementación actual:
class TokenService { private isRefreshing: boolean = false public getToken = async (): Promise<string> => { const accessToken = window.localStorage.getItem('accessToken') if (!accessToken) return Promise.resolve(null) // Check if token has expired const { exp } = JSON.parse(atob(accessToken.split('.')[1])) if (new Date() < new Date(exp * 1e3)) return Promise.resolve(accessToken) if (this.isRefreshing) { // Wait for request to finish and return result } // Refresh token this.isRefreshing = true const refreshedAccessToken = await this.refreshToken() return Promise.resolve(refreshedAccessToken) } } He agregado un indicador isRefreshing que indica si actualmente hay una solicitud de actualización en curso. No estoy seguro de cómo ir desde aquí. ¿Cómo espero a que finalice la solicitud y devuelva su resultado?
Debe hacer referencia a isRefreshing pasando por this primero; no es un identificador independiente.
Al actualizar el token, asigne el resultado de la Promesa a una propiedad en la clase. Esto permitirá que más llamadas de getToken devuelvan esa Promesa, si existe. Si no existe, y si el token actual ha caducado, genere otro.
Debido a que a veces hace Promise.resolve(null) , a veces devuelve null , no una cadena, por lo que debe cambiar la firma de tipo de getToken de manera adecuada.
class TokenService { private tokenPromise: null | Promise<string> = null; public getToken = async (): Promise<string | null> => { const accessToken = window.localStorage.getItem('accessToken') if (!accessToken) return null; // Check if token has expired const { exp } = JSON.parse(atob(accessToken.split('.')[1])) if (new Date() <= new Date(exp * 1e3)) { // no need to retrieve another return accessToken; } if (this.tokenPromise) return this.tokenPromise; this.tokenPromise = this.refreshToken() .catch((error) => { window.localStorage.removeItem('accessToken'); return null; }) .finally(() => { this.tokenPromise = null; }); return this.tokenPromise; } }