11import axios , { AxiosError } from 'axios' ;
2+ import { jwtDecode } from 'jwt-decode' ;
23import useAuthStore from '../hooks/useAuthStore' ;
34import { useErrorStore } from '../hooks/useErrorStore' ;
45
@@ -8,6 +9,9 @@ interface ApiErrorResponse {
89 message : string ;
910}
1011
12+ // 5λΆ λ²νΌ (λ°λ¦¬μ΄)
13+ const BUFFER_TIME = 5 * 60 * 1000 ;
14+
1115// κ³΅ν΅ μ€μ μ κ°μ§ axios μΈμ€ν΄μ€ μμ±
1216const apiClient = axios . create ( {
1317 baseURL : `${ import . meta. env . VITE_API_BASE_URL } /api` ,
@@ -17,9 +21,33 @@ const apiClient = axios.create({
1721
1822// μμ² μΈν°μ
ν°: λͺ¨λ μμ² μ§μ μ μ€νλ¨
1923apiClient . interceptors . request . use ( ( config ) => {
20- const token = useAuthStore . getState ( ) . token ;
24+ const { token, logout } = useAuthStore . getState ( ) ;
2125
2226 if ( token ) {
27+ try {
28+ const decoded = jwtDecode ( token ) ;
29+
30+ if ( decoded . exp ) {
31+ const expTimeMs = decoded . exp * 1000 ;
32+ const now = Date . now ( ) ;
33+
34+ // λ§λ£μκ° 5λΆ μ (νΉμ μ΄λ―Έ μ§λ¨)μ΄λ©΄ κ±°λΆ
35+ if ( expTimeMs - BUFFER_TIME - now <= 0 ) {
36+ // μν κ΄λ¦¬ λ‘κ·Έμμ μ²λ¦¬λ§ μν
37+ // μλ¬ λͺ¨λ¬(showError)κ³Ό 리λ€μ΄λ νΈ(window.location.href)λ
38+ // μ΅μλ¨ App.tsxμ λ§μ΄νΈλ useAutoLogout ν
μμ μΌκ΄μ μΌλ‘ μ²λ¦¬νλλ‘ μμν¨.
39+ // μ¬κΈ°μ μ€λ³΅ νΈμΆ μ λͺ¨λ¬μ΄ 2λ² λ¨λ Race Condition λ°μ κ°λ₯μ± μ°¨λ¨
40+ logout ( ) ;
41+ return Promise . reject ( new Error ( 'TOKEN_EXPIRED_LOCAL' ) ) ;
42+ }
43+ }
44+ } catch {
45+ // λμ½λ© μ€ν¨ μ μ§ννμ§ μμ (μλ²κ° κ±°μ νλλ‘ λκ±°λ μ¬κΈ°μ λ°λ‘ λ§μ)
46+ // 보μμ μ¬κΈ°μ λ°λ‘ λ§λ κ²μ΄ μμ
47+ logout ( ) ;
48+ return Promise . reject ( new Error ( 'INVALID_TOKEN_FORMAT' ) ) ;
49+ }
50+
2351 config . headers . Authorization = `Bearer ${ token } ` ;
2452 }
2553
@@ -36,14 +64,16 @@ apiClient.interceptors.response.use(
3664
3765 // 1. ν ν° λ§λ£ λ± νΉμν κ²½μ° νμΈ λ²νΌ μ‘μ
μ μ
3866 let onConfirm = undefined ;
67+ let confirmText = undefined ;
3968 if ( code === 'TOKEN_EXPIRED' ) {
4069 onConfirm = ( ) => {
4170 window . location . href = '/login' ;
4271 } ;
72+ confirmText = 'λ€μ λ‘κ·ΈμΈνκΈ°' ;
4373 }
4474
45- // 2. μ€ν μ΄λ₯Ό ν΅ν΄ λͺ¨λ¬ λμ°κΈ° (μμ μ£Όμ: message, title, onConfirm)
46- showError ( message , title || 'μ€λ₯ λ°μ' , onConfirm ) ;
75+ // 2. μ€ν μ΄λ₯Ό ν΅ν΄ λͺ¨λ¬ λμ°κΈ° (μμ μ£Όμ: message, title, onConfirm, confirmText )
76+ showError ( message , title || 'μ€λ₯ λ°μ' , onConfirm , confirmText ) ;
4777 } else {
4878 // μλ² μλ΅ μμ²΄κ° μλ κ²½μ° (λ€νΈμν¬ μ€λ₯ λ±)
4979 showError (
0 commit comments