11import axios , { AxiosError , AxiosResponse , InternalAxiosRequestConfig } from "axios" ;
22
3- import { API_URL } from "@/data/constants" ;
43import { PATH } from "@/shared/constants/path" ;
54import { IS_LOGINED } from "@/shared/constants/storage" ;
65import { AxiosErrorResponse , isAxiosErrorResponse } from "@/shared/types/axioxError" ;
76
8- import { safeLocalStorage , safeSessionStorage } from "../storage" ;
9- import { refreshAccessToken } from "./helpers" ;
7+ import { safeSessionStorage } from "../storage" ;
108import { ERROR_CODE } from "./utils/errorCode" ;
119
1210export const clientAxios = axios . create ( {
@@ -28,72 +26,102 @@ clientAxios.interceptors.request.use(
2826 } ,
2927) ;
3028
31- const tokenRefreshPromise : Promise < void > | null = null ;
3229let isLoginAlertShown = false ;
3330
31+ interface TempAxiosErrorResponse extends AxiosErrorResponse {
32+ config : InternalAxiosRequestConfig & { _retry ?: boolean } ;
33+ }
34+
3435// 응답 인터셉터
3536clientAxios . interceptors . response . use (
3637 ( response : AxiosResponse ) => {
3738 return response . data ;
3839 } ,
39- async ( error : AxiosErrorResponse ) => {
40- // if (error.config?.url === API_URL.USER.LOGOUT) {
41- // safeLocalStorage.remove(IS_LOGINED);
42- // window.location.href = PATH.LOGIN;
43- // }
44- // // 로그인이 필요한 요청이거나, 리프레시 토큰 모두 만료시 로그인 페이지로 이동
45- // if (isAxiosErrorResponse(error.response?.data)) {
46- // // 엑세스 토큰 없음
47- // if (
48- // error.response?.data.code === ERROR_CODE.NO_ACCESS_TOKEN ||
49- // error.response?.data.code === ERROR_CODE.REFRESH_TOKEN_EXPIRED
50- // ) {
51- // redirectToLoginOnce();
52- // }
53- // if (error.response?.data.code === ERROR_CODE.LOGIN_REQUIRED) {
54- // // 인증 페이지에서는 로그인 페이지로 이동하지 않음
55- // if (window.location.pathname !== "/auth") {
56- // redirectToLoginOnce();
57- // }
58- // }
59- // if (error.response?.data.code === ERROR_CODE.PAYMENT) {
60- // return Promise.reject(error?.response?.data);
61- // }
62- // // 액세스 토큰 만료
63- // if (error.response?.data.code === ERROR_CODE.ACCESS_TOKEN_EXPIRED) {
64- // try {
65- // // 이미 토큰 재발급이 진행 중이면 완료될 때까지 대기
66- // if (tokenRefreshPromise) {
67- // console.log("@@@@@");
68- // await tokenRefreshPromise;
69- // } else {
70- // // 토큰 재발급 시작
71- // tokenRefreshPromise = refreshAccessToken()
72- // .then(() => {
73- // tokenRefreshPromise = null;
74- // })
75- // .catch((error) => {
76- // tokenRefreshPromise = null;
77- // throw error;
78- // });
79- // }
80- // // 원래 요청 재시도
81- // const originalRequest = error.config;
82- // if (!originalRequest) {
83- // return Promise.reject(error);
84- // }
85- // return clientAxios(originalRequest);
86- // } catch {
87- // if (typeof window !== "undefined") {
88- // redirectToLoginOnce();
89- // return Promise.reject(error?.response?.data);
90- // }
91- // }
92- // }
93- // }
94- // if (error.response?.status === 500) {
95- // return Promise.reject(error?.response?.data);
96- // }
40+ async ( error : TempAxiosErrorResponse ) => {
41+ const original = error . config ;
42+
43+ // get 요청이 아닌 경우 즉시 refreshToken 재발급 및 요청
44+ if ( original ?. method !== "get" && ! original ?. _retry ) {
45+ if ( isAxiosErrorResponse ( error . response ?. data ) ) {
46+ if ( error . response ?. data . code === ERROR_CODE . ACCESS_TOKEN_EXPIRED ) {
47+ original . _retry = true ;
48+
49+ try {
50+ const res = await fetch ( "/api/reissue" , {
51+ method : "POST" ,
52+ headers : {
53+ "Content-Type" : "application/json" ,
54+ } ,
55+ credentials : "include" ,
56+ } ) ;
57+
58+ return res . json ( ) ;
59+ } catch ( e ) {
60+ redirectToLoginOnce ( ) ;
61+
62+ return ;
63+ }
64+ }
65+ }
66+ }
67+
68+ // 로그인이 필요한 요청이거나, 리프레시 토큰 모두 만료시 로그인 페이지로 이동
69+ if ( isAxiosErrorResponse ( error . response ?. data ) ) {
70+ const { code } = error . response ?. data ?? { } ;
71+
72+ // 엑세스 토큰 없음
73+ if ( code === ERROR_CODE . NO_ACCESS_TOKEN || code === ERROR_CODE . REFRESH_TOKEN_EXPIRED ) {
74+ redirectToLoginOnce ( ) ;
75+ }
76+
77+ if ( code === ERROR_CODE . LOGIN_REQUIRED ) {
78+ // 인증 페이지에서는 로그인 페이지로 이동하지 않음
79+ if ( window . location . pathname !== "/auth" ) {
80+ redirectToLoginOnce ( ) ;
81+ }
82+ }
83+
84+ if ( code === ERROR_CODE . PAYMENT ) {
85+ return Promise . reject ( error ?. response ?. data ) ;
86+ }
87+
88+ // // 액세스 토큰 만료
89+ // if (code === ERROR_CODE.ACCESS_TOKEN_EXPIRED) {
90+ // try {
91+ // // 이미 토큰 재발급이 진행 중이면 완료될 때까지 대기
92+ // if (tokenRefreshPromise) {
93+ // console.log("@@@@@");
94+ // await tokenRefreshPromise;
95+ // } else {
96+ // // 토큰 재발급 시작
97+ // tokenRefreshPromise = refreshAccessToken()
98+ // .then(() => {
99+ // tokenRefreshPromise = null;
100+ // })
101+ // .catch((error) => {
102+ // tokenRefreshPromise = null;
103+
104+ // throw error;
105+ // });
106+ // }
107+
108+ // 원래 요청 재시도
109+ // const originalRequest = error.config;
110+
111+ // if (!originalRequest) {
112+ // return Promise.reject(error);
113+ // }
114+
115+ // return clientAxios(originalRequest);
116+ // } catch {
117+ // if (typeof window !== "undefined") {
118+ // redirectToLoginOnce();
119+
120+ // return Promise.reject(error?.response?.data);
121+ // }
122+ // }
123+ // }
124+ }
97125
98126 if ( error ?. response ?. data ) {
99127 return Promise . reject ( {
0 commit comments