1
- import axios , { AxiosError } from 'axios' ;
2
- import { getCookie } from '../utils/cookies' ;
3
- import { setCookie } from '../utils/cookies' ;
1
+ import axios , {
2
+ AxiosError ,
3
+ AxiosHeaders ,
4
+ InternalAxiosRequestConfig ,
5
+ } from 'axios' ;
6
+ import { getCookie , setCookie } from '../utils/cookies' ;
4
7
import { reIssueToken } from './auth' ;
5
8
6
9
export const instance = axios . create ( {
7
10
baseURL : process . env . REACT_APP_BASE_URL ,
8
11
timeout : 10000 ,
9
12
} ) ;
13
+ let isRefreshing = false ;
14
+ let refreshSubscribers : ( ( token : string ) => void ) [ ] = [ ] ;
15
+
16
+ const onRefreshed = ( token : string ) => {
17
+ refreshSubscribers . forEach ( ( callback ) => callback ( token ) ) ;
18
+ refreshSubscribers = [ ] ;
19
+ } ;
10
20
11
21
instance . interceptors . request . use (
12
22
( config ) => {
13
23
const accessToken = getCookie ( 'access_token' ) ;
14
24
if ( accessToken ) {
15
- config . headers = config . headers ?? { } ;
16
- config . headers . Authorization = `Bearer ${ accessToken } ` ;
25
+ config . headers = new AxiosHeaders ( {
26
+ ...config . headers ,
27
+ Authorization : `Bearer ${ accessToken } ` ,
28
+ } ) ;
17
29
}
18
30
return config ;
19
31
} ,
@@ -22,39 +34,65 @@ instance.interceptors.request.use(
22
34
23
35
instance . interceptors . response . use (
24
36
( response ) => response ,
25
- async ( error : AxiosError < AxiosError > ) => {
26
- if ( axios . isAxiosError ( error ) && error . response ) {
27
- const { config } = error ;
37
+ async ( error : AxiosError ) => {
38
+ const originalRequest = error . config as InternalAxiosRequestConfig & {
39
+ _retry ?: boolean ;
40
+ } ;
41
+
42
+ if ( error . response ?. status === 401 || error . response ?. status === 403 ) {
28
43
const refreshToken = getCookie ( 'refresh_token' ) ;
29
- if ( error . response . data . message === 'Expired Token' ) {
30
- if ( refreshToken ) {
31
- try {
32
- const res = await reIssueToken ( refreshToken ) ;
33
- const accessExpired = new Date ( res . access_token_expired_at ) ;
34
- const refreshExpired = new Date ( res . refresh_token_expired_at ) ;
35
-
36
- setCookie ( 'access_token' , res . access_token , {
37
- expires : accessExpired ,
38
- } ) ;
39
44
40
- setCookie ( 'refresh_token' , res . refresh_token , {
41
- expires : refreshExpired ,
42
- } ) ;
45
+ if ( ! refreshToken ) {
46
+ window . location . href = '/login' ;
47
+ return Promise . reject ( error ) ;
48
+ }
43
49
44
- if ( config ?. headers )
45
- config . headers [ 'Authorization' ] = `Bearer ${ res . access_token } ` ;
46
-
47
- return axios ( config ! ) ;
48
- } catch ( error ) {
49
- return Promise . reject ( error ) ;
50
- }
51
- } else {
52
- window . location . href = '/login' ;
53
- }
54
- } else {
50
+ if ( originalRequest . _retry ) {
55
51
return Promise . reject ( error ) ;
56
52
}
53
+ originalRequest . _retry = true ;
54
+
55
+ if ( isRefreshing ) {
56
+ return new Promise ( ( resolve ) => {
57
+ refreshSubscribers . push ( ( token : string ) => {
58
+ originalRequest . headers = new AxiosHeaders ( {
59
+ ...originalRequest . headers ,
60
+ Authorization : `Bearer ${ token } ` ,
61
+ } ) ;
62
+ resolve ( instance ( originalRequest ) ) ;
63
+ } ) ;
64
+ } ) ;
65
+ }
66
+
67
+ isRefreshing = true ;
68
+
69
+ try {
70
+ const res = await reIssueToken ( refreshToken ) ;
71
+ const newAccessToken = res . access_token ;
72
+
73
+ setCookie ( 'access_token' , newAccessToken , {
74
+ expires : new Date ( res . access_token_expired_at ) ,
75
+ } ) ;
76
+
77
+ setCookie ( 'refresh_token' , res . refresh_token , {
78
+ expires : new Date ( res . refresh_token_expired_at ) ,
79
+ } ) ;
80
+
81
+ isRefreshing = false ;
82
+ onRefreshed ( newAccessToken ) ;
83
+
84
+ originalRequest . headers = new AxiosHeaders ( {
85
+ ...originalRequest . headers ,
86
+ Authorization : `Bearer ${ newAccessToken } ` ,
87
+ } ) ;
88
+ return instance ( originalRequest ) ;
89
+ } catch ( err ) {
90
+ isRefreshing = false ;
91
+ window . location . href = '/login' ;
92
+ return Promise . reject ( err ) ;
93
+ }
57
94
}
95
+
58
96
return Promise . reject ( error ) ;
59
97
} ,
60
98
) ;
0 commit comments