Refactor: axios 컨피그 리팩토링, 그러나 덜 됐음.
This commit is contained in:
parent
c547860f62
commit
1547e93a84
@ -1,32 +1,27 @@
|
||||
import axios, { AxiosError, AxiosResponse, InternalAxiosRequestConfig } from 'axios';
|
||||
import useAuthStore from '@/stores/useAuthStore';
|
||||
import { BaseResponse, CustomError, SuccessResponse, RefreshTokenResponse } from '@/types';
|
||||
|
||||
const baseURL = import.meta.env.VITE_API_URL;
|
||||
import { RefreshTokenResponse, ErrorResponse } from '../types';
|
||||
|
||||
const api = axios.create({
|
||||
baseURL,
|
||||
baseURL: `${import.meta.env.VITE_API_URL}/api`,
|
||||
withCredentials: true,
|
||||
});
|
||||
|
||||
let isTokenRefreshing = false;
|
||||
const refreshApi = axios.create({
|
||||
baseURL: `${import.meta.env.VITE_API_URL}/api`,
|
||||
withCredentials: true,
|
||||
});
|
||||
|
||||
type FailedRequest = {
|
||||
resolve: (value?: string | undefined) => void;
|
||||
reject: (reason?: unknown) => void;
|
||||
let isRefreshing = false;
|
||||
let refreshSubscribers: Array<(token: string) => void> = [];
|
||||
|
||||
const subscribeTokenRefresh = (cb: (token: string) => void) => {
|
||||
refreshSubscribers.push(cb);
|
||||
};
|
||||
|
||||
let failedQueue: FailedRequest[] = [];
|
||||
|
||||
const processQueue = (error: Error | null, token: string | undefined = undefined): void => {
|
||||
failedQueue.forEach((prom) => {
|
||||
if (error) {
|
||||
prom.reject(error);
|
||||
} else {
|
||||
prom.resolve(token);
|
||||
}
|
||||
});
|
||||
failedQueue = [];
|
||||
const onRefreshed = (token: string) => {
|
||||
refreshSubscribers.forEach((cb) => cb(token));
|
||||
refreshSubscribers = [];
|
||||
};
|
||||
|
||||
api.interceptors.request.use((config: InternalAxiosRequestConfig) => {
|
||||
@ -39,68 +34,45 @@ api.interceptors.request.use((config: InternalAxiosRequestConfig) => {
|
||||
|
||||
api.interceptors.response.use(
|
||||
(response: AxiosResponse) => response,
|
||||
async (error: AxiosError<BaseResponse<CustomError>>) => {
|
||||
(error: AxiosError<ErrorResponse>) => {
|
||||
const originalRequest = error.config as InternalAxiosRequestConfig & { _retry?: boolean };
|
||||
|
||||
if (error.response?.status === 401 && !originalRequest._retry) {
|
||||
if (isTokenRefreshing) {
|
||||
return new Promise<string | undefined>((resolve, reject) => {
|
||||
failedQueue.push({ resolve, reject });
|
||||
})
|
||||
.then((token) => {
|
||||
if (token && originalRequest.headers) {
|
||||
originalRequest._retry = true;
|
||||
|
||||
if (isRefreshing) {
|
||||
return new Promise<void>((resolve) => {
|
||||
subscribeTokenRefresh((token: string) => {
|
||||
originalRequest.headers.Authorization = `Bearer ${token}`;
|
||||
resolve(api(originalRequest));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
isRefreshing = true;
|
||||
|
||||
return refreshApi
|
||||
.post<RefreshTokenResponse>('/auth/reissue', null, { withCredentials: true })
|
||||
.then(({ data }) => {
|
||||
const newAccessToken = data.accessToken;
|
||||
useAuthStore.getState().setLoggedIn(true, newAccessToken);
|
||||
onRefreshed(newAccessToken);
|
||||
|
||||
originalRequest.headers.Authorization = `Bearer ${newAccessToken}`;
|
||||
return api(originalRequest);
|
||||
})
|
||||
.catch((err) => Promise.reject(err));
|
||||
}
|
||||
|
||||
originalRequest._retry = true;
|
||||
isTokenRefreshing = true;
|
||||
|
||||
try {
|
||||
const response: AxiosResponse<SuccessResponse<RefreshTokenResponse>> = await api.post('/auth/reissue', null, {
|
||||
withCredentials: true,
|
||||
});
|
||||
|
||||
const newAccessToken = response.data.data?.accessToken;
|
||||
if (!newAccessToken) {
|
||||
throw new Error('Invalid token reissue response');
|
||||
}
|
||||
|
||||
useAuthStore.getState().setLoggedIn(true, newAccessToken);
|
||||
processQueue(null, newAccessToken);
|
||||
|
||||
const redirectUri = `/redirect/oauth2?accessToken=${newAccessToken}`;
|
||||
window.location.href = redirectUri;
|
||||
|
||||
return Promise.reject(new Error('Redirecting to retrieve cookies'));
|
||||
} catch (reissueError: unknown) {
|
||||
processQueue(reissueError as Error, undefined);
|
||||
console.error('토큰 재발급 실패:', reissueError);
|
||||
.catch(() => {
|
||||
useAuthStore.getState().clearAuth();
|
||||
console.log('리이슈 실패');
|
||||
window.location.href = '/';
|
||||
return Promise.reject(reissueError);
|
||||
} finally {
|
||||
isTokenRefreshing = false;
|
||||
return Promise.reject(error);
|
||||
})
|
||||
.finally(() => {
|
||||
isRefreshing = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
handleCommonErrors(error);
|
||||
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
const handleCommonErrors = (error: AxiosError<BaseResponse<CustomError>>) => {
|
||||
if (error.response?.status === 400) {
|
||||
alert('잘못된 요청입니다. 다시 시도해 주세요.');
|
||||
} else if (error.response?.status === 403) {
|
||||
alert(error.response?.data?.message);
|
||||
} else {
|
||||
console.error('오류 발생:', error.response?.data?.message || '알 수 없는 오류');
|
||||
}
|
||||
};
|
||||
|
||||
export default api;
|
||||
|
Loading…
Reference in New Issue
Block a user