1- import axios from "axios" ;
1+ import axios , { InternalAxiosRequestConfig } from "axios" ;
22import { getAccessToken , removeAccessToken } from "@/utils/tokenUtils" ;
33import authService from "./authService" ;
44import router from "next/router" ;
5- import useAuthStore from "@/stores/useAuthStore" ;
65
76const apiClient = axios . create ( {
87 baseURL : process . env . NEXT_PUBLIC_API_URL ,
@@ -11,12 +10,31 @@ const apiClient = axios.create({
1110 } ,
1211} ) ;
1312
13+ let isRefreshing = false ;
14+ let failedQueue : Array < {
15+ resolve : ( token : string ) => void ;
16+ reject : ( error : any ) => void ;
17+ } > = [ ] ;
18+
19+ const processQueue = ( error : any , token : string | null = null ) => {
20+ failedQueue . forEach ( ( prom ) => {
21+ if ( error ) {
22+ prom . reject ( error ) ;
23+ } else if ( token ) {
24+ prom . resolve ( token ) ;
25+ }
26+ } ) ;
27+ failedQueue = [ ] ;
28+ } ;
29+
1430// request
1531apiClient . interceptors . request . use (
16- ( config ) => {
17- const accessToken = getAccessToken ( ) ;
18- if ( accessToken ) {
19- config . headers [ "Authorization" ] = `Bearer ${ accessToken } ` ;
32+ ( config : InternalAxiosRequestConfig < any > & { _retry ?: boolean } ) => {
33+ if ( config . url !== "/auth/refresh/token" && ! config . _retry ) {
34+ const accessToken = getAccessToken ( ) ;
35+ if ( accessToken ) {
36+ config . headers [ "Authorization" ] = `Bearer ${ accessToken } ` ;
37+ }
2038 }
2139 return config ;
2240 } ,
@@ -29,20 +47,39 @@ apiClient.interceptors.request.use(
2947apiClient . interceptors . response . use (
3048 ( response ) => response ,
3149 async ( error ) => {
32- if ( error . response && error . response ?. status === 401 ) {
50+ const originalRequest = error . config ;
51+
52+ if ( error . response ?. status === 401 && ! originalRequest . _retry ) {
53+ if ( isRefreshing ) {
54+ try {
55+ const token = await new Promise < string > ( ( resolve , reject ) => {
56+ failedQueue . push ( { resolve, reject } ) ;
57+ } ) ;
58+ originalRequest . headers [ "Authorization" ] = `Bearer ${ token } ` ;
59+ return apiClient ( originalRequest ) ;
60+ } catch ( err ) {
61+ return Promise . reject ( err ) ;
62+ }
63+ }
64+
65+ originalRequest . _retry = true ;
66+ isRefreshing = true ;
67+
3368 try {
34- const newAccessToken = await authService . refreshToken ( ) ;
35- alert ( "새 토큰 발급!" ) ;
36- error . config . headers [ "Authorization" ] = `Bearer ${ newAccessToken } ` ;
37- return apiClient ( error . config ) ;
38- } catch ( error : any ) {
39- console . error ( "토큰 갱신 실패" , error ) ;
69+ const token = await authService . refreshToken ( ) ;
70+ originalRequest . headers [ "Authorization" ] = `Bearer ${ token } ` ;
71+ processQueue ( null , token ) ;
72+ return apiClient ( originalRequest ) ;
73+ } catch ( refreshError ) {
74+ processQueue ( refreshError , null ) ;
4075 removeAccessToken ( ) ;
4176 router . push ( "/login" ) ;
42- alert ( "새로 로그인해주세요!" ) ;
43- return Promise . reject ( error ) ;
77+ return Promise . reject ( refreshError ) ;
78+ } finally {
79+ isRefreshing = false ;
4480 }
4581 }
82+
4683 return Promise . reject ( error ) ;
4784 } ,
4885) ;
0 commit comments