현재 프로젝트에서 JWT 인증 방식을 사용 중이다.
api는 공통 클라이언트를 둬서 관리하고, api 응답코드가 401일 경우 토큰 재발급 요청을 보낸다.
한 페이지에서 여러 개의 api 요청을 날리는 경우에, 토큰 재발급 요청이 여러개 날아가면서 토큰이 꼬이게 되는 문제가 있었다.
이 문제를 api 공통 클라이언트가 1개의 토큰 재발급 요청 프로미스를 공유하도록 해서 해결했다.
기존 코드
동시에 여러번 재발급 요청...
// api 공통 클라이언트
if ([401].includes(response.status)) {
const accessToken = await reissueToken()
// 후처리
}
// 토큰 재발급
asnyc function reissueToken() {
// 생략
return fetch('/reissue')
}
변경 코드
동시 1번만 재발급 요청
// api 공통 클라이언트
if ([401].includes(response.status)) {
const accessToken = await reissueToken()
// 후처리
}
// 토큰 재발급
let reissueTokenPromise = Promise<string> | null
asnyc function reissueToken() {
if(!reissueTokenPromise) {
reissueToeknPromise = fetch('/reissue')
.then(res => {
reissueTokenPromise = null
return res.token
})
}
// 생략
return reissueTokenPromise
}
리팩토링
현재 코드의 문제점은 동시 1번만 요청하도록 하는 로직을 다른 함수에 적용하고 싶을 경우 중복된 코드를 또 써야 한다는 것이다.
토스 slash에 batchRequestsOf 함수를 쓰면 동시 1번만 요청하도록 하는 로직을 따로 함수로 빼서 쓸 수 있다.
기존 로직에 추가로 함수 args 별로 메모이제이션도 적용할 수 있다.
/** @tossdocs-ignore */
import { noop } from './noop';
export function batchRequestsOf<F extends (...args: any[]) => any>(func: F) {
const promiseByKey = new Map<string, Promise<ReturnType<F>>>();
return function (...args: Parameters<F>) {
const key = JSON.stringify(args);
if (promiseByKey.has(key)) {
return promiseByKey.get(key)!;
} else {
const promise = func(...args);
promise.then(() => {
promiseByKey.delete(key);
}, noop);
promiseByKey.set(key, promise);
return promise;
}
} as F;
}
'프론트엔드 > JavaScript, TypeScript' 카테고리의 다른 글
브라우저 탭간 통신하는 3가지 방법 (0) | 2024.08.02 |
---|---|
Typescript와 Duck typing (0) | 2023.12.11 |
조건부 타입과 맵드 타입, 유틸리티 타입 (1) | 2023.03.15 |
타입 가드 (1) | 2023.01.25 |
?. - Optional chaining 연산자 / ?? - Null 병합 연산자 (0) | 2022.08.22 |