동시 여러 개의 토큰 리프레시 요청 관리하기

2024. 7. 28. 18:49·프론트엔드/JavaScript, TypeScript

현재 프로젝트에서 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' 카테고리의 다른 글

CJS와 ESM  (0) 2025.01.12
브라우저 탭간 통신하는 3가지 방법  (0) 2024.08.02
Typescript와 Duck typing  (0) 2023.12.11
조건부 타입과 맵드 타입, 유틸리티 타입  (1) 2023.03.15
타입 가드  (1) 2023.01.25
'프론트엔드/JavaScript, TypeScript' 카테고리의 다른 글
  • CJS와 ESM
  • 브라우저 탭간 통신하는 3가지 방법
  • Typescript와 Duck typing
  • 조건부 타입과 맵드 타입, 유틸리티 타입
정현우12
정현우12
  • 정현우12
    정현우의 개발 블로그
    정현우12
  • 전체
    오늘
    어제
    • 분류 전체보기 (79)
      • 프론트엔드 (56)
        • JavaScript, TypeScript (12)
        • 스타일링 (1)
        • React (13)
        • Next.js (4)
        • 개발 환경 (9)
        • 테스트 (3)
        • 성능 최적화 (11)
        • 함수형 프로그래밍 (2)
        • 구조 (1)
      • 프로젝트 회고 (23)
        • 이미지편집기 개발 (7)
        • 엑셀 다운로드, 업로드 공통 모듈 개발 (4)
        • 사용자 매뉴얼 사이트 개발 (3)
        • 통계자동화 솔루션 개발 (1)
        • 엑셀 편집기 개발 (5)
        • API 플랫폼 (1)
        • 콜센터 솔루션 OB 캠페인 (1)
        • AI 스튜디오 (1)
      • 백엔드 (0)
  • 블로그 메뉴

    • 홈
    • 포트폴리오
    • 태그
  • 인기 글

  • 태그

    웹 성능 최적화
    라이브러리 선정
    React-boilerplate
    JavaScript
    Github Actions
    회고
    frontend
    webpack
    커스텀 훅
    엑셀 에디터
    useReducer
    엑셀
    memoization
    React
    렌더링 성능 최적화
    이미지 편집기
    로딩 성능 최적화
    Next.js
    TypeScript
    사용자 매뉴얼 사이트
  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
정현우12
동시 여러 개의 토큰 리프레시 요청 관리하기
상단으로

티스토리툴바