@@ -2,23 +2,26 @@ import axios, { type AxiosRequestConfig } from "axios";
22
33import useAuthStore from "@/store/useAuthStore" ;
44
5+ const BASE_URL = import . meta. env . VITE_API_BASE_URL ;
6+
7+ if ( ! BASE_URL ) {
8+ throw new Error ( "API 서버 주소(VITE_API_BASE_URL)가 설정되지 않았습니다." ) ;
9+ }
10+
511const axiosConfig : AxiosRequestConfig = {
6- baseURL : import . meta . env . VITE_API_BASE_URL ,
12+ baseURL : BASE_URL ,
713 withCredentials : true ,
814 headers : {
915 "Content-Type" : "application/json" ,
1016 } ,
1117} ;
1218
13- // 일반 API 요청용
1419export const axiosInstance = axios . create ( axiosConfig ) ;
15-
16- // 토큰 재발급 전용
1720export const authInstance = axios . create ( axiosConfig ) ;
1821
1922axiosInstance . interceptors . request . use (
2023 ( config ) => {
21- const token = localStorage . getItem ( "accessToken" ) ;
24+ const token = useAuthStore . getState ( ) . accessToken ;
2225
2326 if ( token ) {
2427 config . headers . Authorization = `Bearer ${ token } ` ;
@@ -31,16 +34,28 @@ axiosInstance.interceptors.request.use(
3134) ;
3235
3336let isRefreshing = false ;
34- let refreshSubscribers : ( ( token : string ) => void ) [ ] = [ ] ;
37+ interface IRefreshSubscriber {
38+ resolve : ( token : string ) => void ;
39+ reject : ( error : unknown ) => void ;
40+ }
41+
42+ let refreshSubscribers : IRefreshSubscriber [ ] = [ ] ;
3543
36- // 대기 요청 처리
3744const onRefreshed = ( accessToken : string ) => {
38- refreshSubscribers . forEach ( ( callback ) => callback ( accessToken ) ) ;
45+ refreshSubscribers . forEach ( ( { resolve } ) => resolve ( accessToken ) ) ;
3946 refreshSubscribers = [ ] ;
4047} ;
4148
42- const addRefreshSubscriber = ( callback : ( token : string ) => void ) => {
43- refreshSubscribers . push ( callback ) ;
49+ const onRefreshFailed = ( error : unknown ) => {
50+ refreshSubscribers . forEach ( ( { reject } ) => reject ( error ) ) ;
51+ refreshSubscribers = [ ] ;
52+ } ;
53+
54+ const addRefreshSubscriber = (
55+ resolve : ( token : string ) => void ,
56+ reject : ( error : unknown ) => void ,
57+ ) => {
58+ refreshSubscribers . push ( { resolve, reject } ) ;
4459} ;
4560
4661axiosInstance . interceptors . response . use (
@@ -50,50 +65,48 @@ axiosInstance.interceptors.response.use(
5065 async ( error ) => {
5166 const originalRequest = error . config ;
5267
53- // 401 에러 감지
5468 if ( error . response ?. status === 401 ) {
55- // 재발급 진행 중: 대기열 등록
5669 if ( isRefreshing ) {
57- return new Promise ( ( resolve ) => {
58- addRefreshSubscriber ( ( accessToken : string ) => {
59- originalRequest . headers . Authorization = `Bearer ${ accessToken } ` ;
60- resolve ( axiosInstance ( originalRequest ) ) ;
61- } ) ;
70+ return new Promise ( ( resolve , reject ) => {
71+ addRefreshSubscriber (
72+ ( accessToken : string ) => {
73+ originalRequest . headers . Authorization = `Bearer ${ accessToken } ` ;
74+ resolve ( axiosInstance ( originalRequest ) ) ;
75+ } ,
76+ ( refreshError : unknown ) => {
77+ reject ( refreshError ) ;
78+ } ,
79+ ) ;
6280 } ) ;
6381 }
6482
65- // 재발급 실패: 로그아웃
6683 if (
6784 originalRequest . url ?. includes ( "/api/auth/reissue" ) ||
6885 originalRequest . _retry
6986 ) {
70- localStorage . removeItem ( "accessToken" ) ;
87+ useAuthStore . getState ( ) . logout ( ) ;
7188 return Promise . reject ( error ) ;
7289 }
7390
74- // 첫 401: 재발급 시도
7591 originalRequest . _retry = true ;
7692 isRefreshing = true ;
7793
7894 try {
7995 const { data } = await authInstance . post ( "/api/auth/reissue" ) ;
8096
8197 const newAccessToken = data . data . accessToken ;
82- localStorage . setItem ( "accessToken" , newAccessToken ) ;
8398
84- // 대기 요청 일괄 처리
99+ useAuthStore . getState ( ) . setAccessToken ( newAccessToken ) ;
85100 onRefreshed ( newAccessToken ) ;
86101
87- // 현재 요청 재시도
88102 originalRequest . headers . Authorization = `Bearer ${ newAccessToken } ` ;
89103 return axiosInstance ( originalRequest ) ;
90104 } catch ( refreshError ) {
91- // 재발급 실패: 로그아웃
92- console . error ( "Token reissue failed:" , refreshError ) ;
105+ console . error ( "토큰 재발급 실패:" , refreshError ) ;
106+ onRefreshFailed ( refreshError ) ;
93107 useAuthStore . getState ( ) . logout ( ) ;
94108 return Promise . reject ( refreshError ) ;
95109 } finally {
96- // 상태 초기화
97110 isRefreshing = false ;
98111 refreshSubscribers = [ ] ;
99112 }
0 commit comments