-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathinstance.ts
More file actions
105 lines (90 loc) · 2.81 KB
/
instance.ts
File metadata and controls
105 lines (90 loc) · 2.81 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
import axios, { AxiosError } from 'axios';
import type { InternalAxiosRequestConfig } from 'axios';
import {
getAccessToken,
getRefreshToken,
setTokens,
clearTokens,
} from '@/shared/utils/token';
import type { ApiResponse, TokenData } from '@/shared/types/authtypes';
const BASE_URL = process.env.NEXT_PUBLIC_BACKEND_URL;
//토큰이 필요한 요청용 인스턴스
export const apiWithToken = axios.create({
baseURL: BASE_URL,
withCredentials: true,
});
// 토큰이 필요 없는 요청용 인스턴스
export const apiAuth = axios.create({
baseURL: BASE_URL,
withCredentials: true,
});
// 요청 인터셉터 - 액세스 토큰 첨부
apiWithToken.interceptors.request.use(
(config) => {
const token = getAccessToken();
if (token) config.headers.Authorization = `Bearer ${token}`;
return config;
},
(error) => Promise.reject(error),
);
// 응답 인터셉터 - 토큰 재발급 처리
let isRefreshing = false;
let failedQueue: {
resolve: (token?: string) => void;
reject: (error: unknown) => void;
}[] = [];
const processQueue = (error: unknown, token: string | null = null) => {
failedQueue.forEach((prom) => {
if (error) prom.reject(error);
else prom.resolve(token ?? '');
});
failedQueue = [];
};
apiWithToken.interceptors.response.use(
(response) => response,
async (error: AxiosError<ApiResponse<unknown>>) => {
const originalRequest = error.config as InternalAxiosRequestConfig & {
_retry?: boolean;
};
if (error.response?.status === 401 && !originalRequest._retry) {
if (isRefreshing) {
return new Promise((resolve, reject) => {
failedQueue.push({
resolve: (token?: string) => {
originalRequest.headers.Authorization = 'Bearer ' + token;
resolve(apiWithToken(originalRequest));
},
reject,
});
});
}
originalRequest._retry = true;
isRefreshing = true;
try {
// refreshToken 가져옴
const refreshToken = getRefreshToken();
const { data } = await axios.post<ApiResponse<TokenData>>(
`${BASE_URL}/api/auth/token/refresh`,
{ refreshToken },
{ withCredentials: true },
);
const { accessToken, refreshToken: newRefresh } = data.data;
setTokens(accessToken, newRefresh);
apiWithToken.defaults.headers.common.Authorization =
'Bearer ' + accessToken;
processQueue(null, accessToken);
return apiWithToken(originalRequest);
} catch (err) {
processQueue(err, null);
clearTokens();
if (typeof window !== 'undefined') {
window.location.href = '/auth';
}
return Promise.reject(err);
} finally {
isRefreshing = false;
}
}
return Promise.reject(error);
},
);