Skip to content

Commit

Permalink
Revert "[#596] accessToken이 만료된 직후 다른 페이지 접근할 때 에러 페이지를 보여주지 않고 새로고침 (#…
Browse files Browse the repository at this point in the history
…600)"

This reverts commit 59407c6.
  • Loading branch information
gxxrxn authored Aug 20, 2024
1 parent 4fd98ad commit 06feaa0
Show file tree
Hide file tree
Showing 9 changed files with 64 additions and 125 deletions.
46 changes: 28 additions & 18 deletions src/apis/core/axios.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import axios, { CreateAxiosDefaults, InternalAxiosRequestConfig } from 'axios';

import { AuthRefreshIgnoredError } from '@/types/customError';
import { ACCESS_TOKEN_STORAGE_KEY, SERVICE_ERROR_MESSAGE } from '@/constants';
import {
isAuthFailedError,
isAuthRefreshError,
isAxiosErrorWithCustomCode,
} from '@/utils/helpers';
import isClient from '@/utils/isClient';
import webStorage from '@/utils/storage';

const storage = webStorage(ACCESS_TOKEN_STORAGE_KEY);
Expand Down Expand Up @@ -38,6 +38,10 @@ const requestHandler = (config: InternalAxiosRequestConfig) => {
return config;
};

/** api 요청이 병렬적으로 이뤄질 때,
* 토큰 업데이트는 한번만 요청하기 위해 사용되는 flag 변수 */
let isRefreshing = false;

const responseHandler = async (error: unknown) => {
if (isAxiosErrorWithCustomCode(error)) {
const { config: originRequest, response } = error;
Expand All @@ -46,7 +50,7 @@ const responseHandler = async (error: unknown) => {

console.warn(code, message);

if (originRequest && isAuthRefreshError(code)) {
if (originRequest && isAuthRefreshError(code) && !isRefreshing) {
return silentRefresh(originRequest);
}

Expand All @@ -62,39 +66,45 @@ const responseHandler = async (error: unknown) => {

const silentRefresh = async (originRequest: InternalAxiosRequestConfig) => {
try {
isRefreshing = true;

const newToken = await updateToken();
storage.set(newToken);
setAxiosAuthHeader(originRequest, newToken);

isRefreshing = false;

return await publicApi(originRequest);
} catch (error) {
removeToken();
isRefreshing = false;

return Promise.reject(error);
}
};

/** api 요청이 병렬적으로 이뤄질 때,
* 토큰 업데이트는 한번만 요청하기 위해 사용되는 flag 변수 */
let isTokenRefreshing = false;
const updateToken = async () => {
try {
const {
data: { accessToken },
} = await axios.post<{ accessToken: string }>('/service-api/auth/token');

const updateToken = () =>
new Promise<string>((resolve, reject) => {
if (isTokenRefreshing) {
reject(new AuthRefreshIgnoredError('Already trying to refresh token'));
return;
if (!accessToken) {
throw new Error('새로운 accessToken을 받아오지 못했어요.');
}

isTokenRefreshing = true;

axios
.post<{ accessToken: string }>('/service-api/auth/token')
.then(({ data }) => resolve(data.accessToken))
.catch(reason => reject(reason))
.finally(() => (isTokenRefreshing = false));
});
return accessToken;
} catch (error) {
return Promise.reject(error);
}
};

const removeToken = () => {
storage.remove();

if (isClient()) {
window.location.reload();
}
};

const setAxiosAuthHeader = (
Expand Down
29 changes: 29 additions & 0 deletions src/app/error.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
'use client';

import Button from '@/v1/base/Button';
import Image from 'next/image';
import { useRouter } from 'next/navigation';

export const ErrorPage = () => {
const router = useRouter();

return (
<div className="absolute left-0 top-0 flex h-full w-full flex-col items-center justify-center gap-[2rem]">
<Image src="/images/loading.gif" width={230} height={160} alt="loading" />
<div className="font-heading">
<span className="font-bold text-main-900">다독이</span>도 몰라요~ 왜
이래요~
</div>
<Button
size="large"
colorScheme="main"
fill={false}
onClick={() => router.replace('/')}
>
처음으로 돌아가기
</Button>
</div>
);
};

export default ErrorPage;
38 changes: 0 additions & 38 deletions src/app/global-error.tsx

This file was deleted.

5 changes: 1 addition & 4 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import ContextProvider from '@/components/ContextProvider';
import AuthFailedErrorBoundary from '@/components/AuthFailedErrorBoundary';
import Layout from '@/v1/layout/Layout';

import { LineSeedKR } from '@/styles/font';
Expand All @@ -19,9 +18,7 @@ const RootLayout = ({ children }: { children: React.ReactNode }) => {
{/* @todo Chakra 제거시 app-layout 프로퍼티 제거. */}
<body className={`${LineSeedKR.variable} app-layout font-lineseed`}>
<Layout>
<ContextProvider>
<AuthFailedErrorBoundary>{children}</AuthFailedErrorBoundary>
</ContextProvider>
<ContextProvider>{children}</ContextProvider>
</Layout>
</body>
</html>
Expand Down
43 changes: 0 additions & 43 deletions src/components/AuthFailedErrorBoundary.tsx

This file was deleted.

6 changes: 5 additions & 1 deletion src/components/ContextProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
'use client';

import { ReactNode } from 'react';
import { ErrorBoundary } from 'react-error-boundary';
import { RecoilRoot } from 'recoil';

import ErrorPage from '@/app/error';
import ChakraThemeProvider from '@/components/ChakraThemeProvider';
import ReactQueryProvider from '@/components/ReactQueryProvider';
import ToastProvider from '@/v1/base/Toast/ToastProvider';
Expand All @@ -12,7 +14,9 @@ const ContextProvider = ({ children }: { children: ReactNode }) => {
<RecoilRoot>
<ReactQueryProvider>
<ChakraThemeProvider>
<ToastProvider>{children}</ToastProvider>
<ErrorBoundary fallbackRender={ErrorPage}>
<ToastProvider>{children}</ToastProvider>
</ErrorBoundary>
</ChakraThemeProvider>
</ReactQueryProvider>
</RecoilRoot>
Expand Down
10 changes: 1 addition & 9 deletions src/components/ReactQueryProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import AuthRefreshIgnoredError from '@/types/customError/AuthRefreshIgnoredError';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
import { NextPage } from 'next/types';
Expand All @@ -15,18 +14,11 @@ const ReactQueryProvider: NextPage<PropTypes> = ({ children }) => {
defaultOptions: {
queries: {
refetchOnWindowFocus: false,
retry: (_count, error) => {
if (error instanceof AuthRefreshIgnoredError) {
return true;
}

return false;
},
retry: false,
},
},
})
);

return (
<QueryClientProvider client={queryClient}>
<ReactQueryDevtools initialIsOpen={false} position="bottom-right" />
Expand Down
11 changes: 0 additions & 11 deletions src/types/customError/AuthRefreshIgnoredError.ts

This file was deleted.

1 change: 0 additions & 1 deletion src/types/customError/index.ts

This file was deleted.

0 comments on commit 06feaa0

Please sign in to comment.