Refactor: Axios config 리팩토링
This commit is contained in:
parent
97816e30db
commit
eb30abefcc
@ -1,32 +1,17 @@
|
|||||||
import axios, { AxiosError, AxiosResponse, InternalAxiosRequestConfig } from 'axios';
|
import axios, { AxiosError, AxiosResponse, InternalAxiosRequestConfig } from 'axios';
|
||||||
import useAuthStore from '@/stores/useAuthStore';
|
import useAuthStore from '@/stores/useAuthStore';
|
||||||
import { RefreshTokenResponse, ErrorResponse } from '../types';
|
import { RefreshTokenResponse } from '../types';
|
||||||
|
|
||||||
|
const REFRESH_URL = '/auth/reissue';
|
||||||
const api = axios.create({
|
const api = axios.create({
|
||||||
baseURL: `${import.meta.env.VITE_API_URL}/api`,
|
baseURL: `${import.meta.env.VITE_API_URL}`,
|
||||||
withCredentials: true,
|
withCredentials: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
const refreshApi = axios.create({
|
|
||||||
baseURL: `${import.meta.env.VITE_API_URL}/api`,
|
|
||||||
withCredentials: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
let isRefreshing = false;
|
|
||||||
let refreshSubscribers: Array<(token: string) => void> = [];
|
|
||||||
|
|
||||||
const subscribeTokenRefresh = (cb: (token: string) => void) => {
|
|
||||||
refreshSubscribers.push(cb);
|
|
||||||
};
|
|
||||||
|
|
||||||
const onRefreshed = (token: string) => {
|
|
||||||
refreshSubscribers.forEach((cb) => cb(token));
|
|
||||||
refreshSubscribers = [];
|
|
||||||
};
|
|
||||||
|
|
||||||
api.interceptors.request.use((config: InternalAxiosRequestConfig) => {
|
api.interceptors.request.use((config: InternalAxiosRequestConfig) => {
|
||||||
const accessToken = useAuthStore.getState().accessToken;
|
const accessToken = useAuthStore.getState().accessToken;
|
||||||
if (accessToken && config.headers) {
|
|
||||||
|
if (accessToken) {
|
||||||
config.headers.Authorization = `Bearer ${accessToken}`;
|
config.headers.Authorization = `Bearer ${accessToken}`;
|
||||||
}
|
}
|
||||||
return config;
|
return config;
|
||||||
@ -34,45 +19,28 @@ api.interceptors.request.use((config: InternalAxiosRequestConfig) => {
|
|||||||
|
|
||||||
api.interceptors.response.use(
|
api.interceptors.response.use(
|
||||||
(response: AxiosResponse) => response,
|
(response: AxiosResponse) => response,
|
||||||
(error: AxiosError<ErrorResponse>) => {
|
(error: AxiosError) => {
|
||||||
const originalRequest = error.config as InternalAxiosRequestConfig & { _retry?: boolean };
|
if (error.response?.status !== 401 || error.request.responseURL?.includes(REFRESH_URL)) {
|
||||||
|
return Promise.reject(error);
|
||||||
if (error.response?.status === 401 && !originalRequest._retry) {
|
|
||||||
originalRequest._retry = true;
|
|
||||||
|
|
||||||
if (isRefreshing) {
|
|
||||||
return new Promise<void>((resolve) => {
|
|
||||||
subscribeTokenRefresh((token: string) => {
|
|
||||||
originalRequest.headers.Authorization = `Bearer ${token}`;
|
|
||||||
resolve(api(originalRequest));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
isRefreshing = true;
|
return api
|
||||||
|
.post<RefreshTokenResponse>(REFRESH_URL)
|
||||||
return refreshApi
|
|
||||||
.post<RefreshTokenResponse>('/auth/reissue', null, { withCredentials: true })
|
|
||||||
.then(({ data }) => {
|
.then(({ data }) => {
|
||||||
const newAccessToken = data.accessToken;
|
console.log(data);
|
||||||
useAuthStore.getState().setLoggedIn(true, newAccessToken);
|
const { accessToken } = data;
|
||||||
onRefreshed(newAccessToken);
|
useAuthStore.getState().setLoggedIn(true, accessToken);
|
||||||
|
if (error.config) {
|
||||||
originalRequest.headers.Authorization = `Bearer ${newAccessToken}`;
|
return api(error.config);
|
||||||
return api(originalRequest);
|
}
|
||||||
|
return Promise.reject(error);
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch((error) => {
|
||||||
useAuthStore.getState().clearAuth();
|
useAuthStore.getState().clearAuth();
|
||||||
console.log('리이슈 실패');
|
|
||||||
window.location.href = '/';
|
window.location.href = '/';
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
isRefreshing = false;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return Promise.reject(error);
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
export default api;
|
export default api;
|
||||||
|
@ -18,7 +18,7 @@ export default function Home() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
const handleGoogleSignIn = () => {
|
const handleGoogleSignIn = () => {
|
||||||
window.location.href = `${BASE_URL}/api/login/oauth2/authorization/google`;
|
window.location.href = `${BASE_URL}/login/oauth2/authorization/google`;
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -43,17 +43,6 @@ export default function Home() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{!isLoggedIn ? (
|
{!isLoggedIn ? (
|
||||||
// <Link
|
|
||||||
// to={`${BASE_URL}/api/login/oauth2/authorization/google`}
|
|
||||||
// // onClick={handleGoogleSignIn}
|
|
||||||
// className="mb-4 transition hover:opacity-90 focus:outline-none focus:ring-2 focus:ring-gray-300 active:opacity-80"
|
|
||||||
// >
|
|
||||||
// <img
|
|
||||||
// src={GoogleLogo}
|
|
||||||
// alt="Sign in with Google"
|
|
||||||
// className="h-auto w-full"
|
|
||||||
// />
|
|
||||||
// </Link>
|
|
||||||
<button
|
<button
|
||||||
onClick={handleGoogleSignIn}
|
onClick={handleGoogleSignIn}
|
||||||
className="mb-4 transition hover:opacity-90 focus:outline-none focus:ring-2 focus:ring-gray-300 active:opacity-80"
|
className="mb-4 transition hover:opacity-90 focus:outline-none focus:ring-2 focus:ring-gray-300 active:opacity-80"
|
||||||
|
Loading…
Reference in New Issue
Block a user