-
Notifications
You must be signed in to change notification settings - Fork 3
Fix: 401에러 토큰 갱신 로직 apiClient hook에도 추가 #544
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
WalkthroughNext.js 설정에서 프로덕션 빌드 시 콘솔 로그 제거 옵션이 비활성화되었습니다. 미들웨어의 리프레시 토큰 실패 시 리다이렉트 로직이 제거되고, 토큰 갱신 엔드포인트 명칭이 변경되었습니다. 클라이언트 상태 관리와 에러 처리 로직이 리팩토링 및 강화되었으며, 일부 컴포넌트에 React Suspense가 추가되었습니다. accessToken 쿠키의 만료 시간이 테스트 목적으로 10초로 단축되었습니다. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Browser
participant ClientProvider
participant ZustandStore
participant Router
User->>Browser: 페이지 접근 (세션 만료 URL 포함)
Browser->>ClientProvider: 컴포넌트 마운트
ClientProvider->>Browser: URL 쿼리 파싱
alt error=SESSION_EXPIRED
ClientProvider->>ZustandStore: clearUser() 호출
end
ClientProvider->>Router: 렌더링 계속
sequenceDiagram
participant Middleware
participant Backend
participant Logger
Middleware->>Backend: 토큰 갱신 요청 (NEW_TOKEN 엔드포인트)
Backend-->>Middleware: 응답(성공/실패)
alt 실패
Middleware->>Logger: "refresh token expired or failed" 로그 출력
Note right of Middleware: 더 이상 리다이렉트 없음
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
100df0d to
f3abb17
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
next.config.ts(1 hunks)src/middleware.ts(2 hunks)src/shared/constants/endpoints.ts(1 hunks)src/shared/libs/formatErrorResponseHooks.ts(2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
src/shared/libs/formatErrorResponseHooks.ts (2)
src/shared/schemas/error.ts (1)
errorResponseSchema(3-6)src/shared/constants/routes.ts (2)
ROUTES(1-18)ERROR_CODES(32-39)
src/middleware.ts (1)
src/shared/constants/endpoints.ts (1)
API_ENDPOINTS(29-81)
🔇 Additional comments (7)
src/shared/constants/endpoints.ts (1)
33-33: 상수 이름 변경이 적절합니다.
REFRESH_TOKEN에서NEW_TOKEN으로의 이름 변경이 일관성 있게 적용되었습니다. 실제 엔드포인트 경로는 그대로 유지되어 기능상 문제가 없습니다.next.config.ts (1)
17-17: 프로덕션에서 console.log 제거 기능이 비활성화되었습니다.디버깅 목적으로 임시로 비활성화한 것으로 보이지만, 프로덕션 환경에서 console.log가 남아있으면 성능에 영향을 줄 수 있고 민감한 정보가 노출될 위험이 있습니다.
토큰 갱신 로직 디버깅이 완료되면 다시 활성화하는 것을 고려해보세요:
- // removeConsole: process.env.NODE_ENV === 'production', + removeConsole: process.env.NODE_ENV === 'production',src/middleware.ts (3)
110-110: 주석이 더 명확해졌습니다."엑세스토큰 갱신" 문구로 주석이 더 명확하게 수정되었습니다.
113-115: 변수명과 엔드포인트 참조가 일관성 있게 업데이트되었습니다.
refreshResponse에서newTokenResponse로의 변수명 변경과API_ENDPOINTS.AUTH.NEW_TOKEN사용이 상수 파일의 변경사항과 일치합니다.
124-125: 변경된 변수명이 일관성 있게 적용되었습니다.
newTokenResponse변수가 후속 로직에서도 올바르게 사용되었습니다.src/shared/libs/formatErrorResponseHooks.ts (2)
8-48: 에러 훅 함수 추출로 코드 구조가 개선되었습니다.인라인으로 구현되어 있던
beforeError로직을 별도의beforeErrorHook함수로 추출하여 가독성과 유지보수성이 향상되었습니다.
84-85: 훅 배열 구조로 변경되었습니다.추출된 훅 함수들이 배열 형태로 할당되어 확장성이 향상되었습니다.
| const afterResponseHook = async ( | ||
| request: Request, | ||
| options: Options, | ||
| response: Response, | ||
| ) => { | ||
| if (response.status === 401) { | ||
| console.error('클라이언트 측에서 401 에러 감지. 세션이 만료되었습니다.'); | ||
|
|
||
| const redirectUrl = new URL(ROUTES.SIGNIN, window.location.origin); | ||
| redirectUrl.searchParams.set('error', ERROR_CODES.SESSION_EXPIRED); | ||
| window.location.href = redirectUrl.toString(); | ||
| } | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
클라이언트 측 401 에러 처리가 추가되었습니다.
401 응답 시 로그인 페이지로 리다이렉트하는 로직이 추가되어 미들웨어의 서버 측 토큰 갱신 로직을 보완합니다. 하지만 몇 가지 개선사항을 고려해보세요:
window.location.href대신 Next.js의useRouter나router.push()를 사용하는 것이 더 적절할 수 있습니다.- 여러 API 호출이 동시에 401을 받을 경우 중복 리다이렉트가 발생할 수 있습니다.
다음 스크립트로 이 훅이 사용되는 곳들을 확인하여 클라이언트 측에서만 실행되는지 검증해보세요:
🏁 Script executed:
#!/bin/bash
# Description: formatErrorResponseHooks 사용처 확인
rg -A 5 -B 5 "formatErrorResponseHooks"Length of output: 20760
클라이언트 전용 401 리다이렉트 로직 확인 및 개선 제안
formatErrorResponseHooks의 afterResponseHook은 Next.js 클라이언트 페이지(.tsx)와 클라이언트 훅(useSignupMutation, useSigninMutation, useSignoutMutation 등)에서만 사용되므로 서버 사이드에서 window를 참조하지 않아 안전합니다.
다만 아래 개선 사항을 검토해주세요:
- Next.js 라우터 활용
•const router = useRouter()후
router.push({ pathname: ROUTES.SIGNIN, query: { error: ERROR_CODES.SESSION_EXPIRED } }) - 다중 401 처리 시 중복 리다이렉트 방지
• 전역 플래그(Ref, Zustand 등)나 Debounce 로직을 추가하여 최초 호출 1회만 실행
파일: src/shared/libs/formatErrorResponseHooks.ts (Lines 50–62)
🤖 Prompt for AI Agents
In src/shared/libs/formatErrorResponseHooks.ts lines 50 to 62, the current 401
error handling uses window.location.href for redirection, which can be improved
by using Next.js's useRouter for client-side navigation. Refactor the hook to
access the router and replace window.location.href with router.push including
the error query parameter. Additionally, implement a global flag or debounce
mechanism to prevent multiple rapid 401 responses from triggering repeated
redirects, ensuring only the first 401 triggers the redirect.
f3abb17 to
bfc9b60
Compare
bfc9b60 to
10f7e5f
Compare
10f7e5f to
aba2cd7
Compare
✅ Preview Deployment Ready!🔗 Preview URL: https://roam-ready-mbmbkm0yr-yongmins-projects-bf5f7733.vercel.app This preview will be automatically updated on new commits. |
✅ Preview Deployment Ready!🔗 Preview URL: https://roam-ready-7coe7l9c6-yongmins-projects-bf5f7733.vercel.app This preview will be automatically updated on new commits. |
c4a4383 to
648da98
Compare
✅ Preview Deployment Ready!🔗 Preview URL: https://roam-ready-c7d1jfltf-yongmins-projects-bf5f7733.vercel.app This preview will be automatically updated on new commits. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🔭 Outside diff range comments (2)
src/domain/User/hooks/useProfileImageMutation.ts (2)
15-18: 사용되지 않는 MutationContext 인터페이스.
onMutate콜백이 제거되었지만MutationContext인터페이스가 여전히 남아있습니다.onError와onSettled에서context?.previewUrl을 사용하므로 현재는 항상 undefined가 될 것입니다.다음과 같이 수정하는 것을 권장합니다:
-interface MutationContext { - previousImageUrl: string; - previewUrl: string; -}그리고
onError,onSettled에서 context 관련 로직도 제거:-onError: (error, _variables, context?: MutationContext) => { +onError: (error) => { console.error('이미지 업로드 실패:', error); - // 이전 이미지로 롤백 - if (context?.previousImageUrl) { - setProfileImageUrl(context.previousImageUrl); - onImageChange?.(context.previousImageUrl); - } - - // 미리보기 URL 메모리 해제 - if (context?.previewUrl) { - URL.revokeObjectURL(context.previewUrl); - }
21-33: 문서와 구현이 일치하지 않습니다.주석에서는 여전히 "낙관적 업데이트"와 "즉시 미리보기" 로직을 설명하고 있지만, 실제 구현에서는 해당 기능이 모두 제거되었습니다.
문서를 현재 구현에 맞게 업데이트해 주세요:
/** - * 프로필 이미지 업로드(Mutation)와 낙관적 업데이트 로직을 처리하는 커스텀 훅입니다. + * 프로필 이미지 업로드(Mutation)를 처리하는 커스텀 훅입니다. * - * ### 낙관적 업데이트 플로우: - * 1. **즉시 미리보기**: 파일 선택 시 즉시 미리보기 URL로 UI 업데이트 - * 2. **백그라운드 업로드**: 동시에 서버로 실제 파일 업로드 진행 - * 3. **성공 시**: 서버 URL로 교체 및 미리보기 URL 메모리 해제 - * 4. **실패 시**: 이전 이미지로 롤백 및 에러 메시지 표시 + * ### 업로드 플로우: + * 1. **파일 업로드**: 서버로 파일 업로드 진행 + * 2. **성공 시**: 서버 응답의 이미지 URL로 상태 업데이트 + * 3. **실패 시**: 에러 메시지 표시 * * @param setProfileImageUrl - 부모 컴포넌트의 이미지 URL 상태를 업데이트하는 함수 - * @param initialImageUrl - 롤백 시 돌아갈 초기 이미지 URL * @param onImageChange - 이미지 변경 시 호출되는 콜백 함수 * @returns TanStack Query의 `useMutation` 결과 객체 (`mutate` 함수, `isPending` 상태 등) */
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
src/app/_components/ClientProvider.tsx(3 hunks)src/domain/Auth/utils/setAuthCookies.ts(2 hunks)src/domain/User/hooks/useProfileImageMutation.ts(2 hunks)src/middleware.ts(4 hunks)src/shared/libs/formatErrorResponseHooks.ts(2 hunks)
✅ Files skipped from review due to trivial changes (1)
- src/domain/Auth/utils/setAuthCookies.ts
🚧 Files skipped from review as they are similar to previous changes (2)
- src/middleware.ts
- src/shared/libs/formatErrorResponseHooks.ts
🔇 Additional comments (5)
src/app/_components/ClientProvider.tsx (2)
4-11: 새로운 의존성 추가가 적절합니다.세션 만료 처리를 위한 필수 의존성들이 올바르게 추가되었습니다.
useSearchParams,ERROR_CODES,useRoamReadyStore모두 구현된 로직에 필요한 imports입니다.
21-24: 문서화가 잘 되어있습니다.새로운 세션 만료 처리 기능에 대한 설명이 명확하고 상세하게 작성되어 있습니다. UX 방어로직이라는 목적도 잘 설명되어 있습니다.
src/domain/User/hooks/useProfileImageMutation.ts (3)
1-7: 불필요한 import가 정리되었습니다.
useQueryClient와 관련 타입들이 제거되어 훅이 더 단순해졌습니다. 이는 전역 상태 관리 책임을 다른 곳으로 이관한 것과 일치합니다.
42-52: onSuccess 콜백이 단순화되어 좋습니다.전역 상태 관리 로직이 제거되고 로컬 상태 업데이트에만 집중하도록 변경되었습니다. 이는 관심사의 분리 원칙에 부합합니다.
9-13: InitialImageUrl 파라미터는 여전히 존재하여 Breaking Change 없음
MutationHookProp 인터페이스와 useProfileImageMutation 호출부 모두initialImageUrl을 포함하고 있으므로 제거된 적이 없으며, 깨지는 변경사항이 없습니다. 해당 리뷰 코멘트는 무시해 주세요.Likely an incorrect or invalid review comment.
| const clearUser = useRoamReadyStore((state) => state.clearUser); | ||
| const searchParams = useSearchParams(); | ||
|
|
||
| useEffect(() => { | ||
| if (searchParams?.get('error') === ERROR_CODES.SESSION_EXPIRED) { | ||
| clearUser(); | ||
| } | ||
| }, [searchParams, clearUser]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
세션 만료 처리 로직을 검증해 주세요.
구현 로직은 올바르게 작성되었지만, 다음 사항들을 확인해 주세요:
ERROR_CODES.SESSION_EXPIRED상수값이 실제 미들웨어나 API 응답에서 사용하는 값과 일치하는지clearUser()함수가 모든 필요한 사용자 상태를 완전히 초기화하는지- 다른 에러 코드들도 비슷한 방식으로 처리가 필요한지
다음 스크립트를 실행하여 ERROR_CODES 상수와 clearUser 함수의 구현을 확인해 주세요:
🏁 Script executed:
#!/bin/bash
# ERROR_CODES 상수 정의 확인
echo "=== ERROR_CODES 상수 정의 ==="
rg -A 10 "ERROR_CODES" --type ts
echo "=== clearUser 함수 구현 확인 ==="
ast-grep --pattern 'clearUser: $_'
echo "=== 세션 만료 관련 다른 사용처 확인 ==="
rg "SESSION_EXPIRED" --type ts -A 3 -B 3Length of output: 16835
다음 스크립트를 실행하여 clearUser 함수의 정의 위치와 구현 내용을 확인해 주세요.
🏁 Script executed:
#!/bin/bash
# clearUser 함수 정의가 선언된 파일 찾기
echo "=== clearUser 함수 정의 위치 ==="
rg -n "clearUser" -g "src/shared/store/**/*.{ts,tsx}"
# clearUser 함수 구현 전체 확인
echo "=== clearUser 함수 구현 확인 (문맥 포함) ==="
rg -n -B2 -A5 "clearUser" -g "src/shared/store/**/*.{ts,tsx}"Length of output: 257
다음과 같이 전 범위에서 clearUser 정의를 찾는 스크립트를 실행해주세요.
위 결과를 통해 clearUser가 선언된 파일과 구현 내용을 확인한 뒤 다시 공유해주세요.
🏁 Script executed:
#!/bin/bash
# 전 범위에서 clearUser 호출/정의 위치 확인
echo "=== clearUser 모든 출현 위치 ==="
rg -n "clearUser" -A3 -B3Length of output: 6961
세션 만료 처리 로직 검증 및 추가 캐시 초기화 제안
-
ERROR_CODES.SESSION_EXPIRED
- 정의(src/shared/constants/routes.ts)된 값
'session_expired'이 formatErrorResponseHooks, 테스트 페이지 등에서 일관되게 사용되고 있어 매칭에 문제 없습니다.
- 정의(src/shared/constants/routes.ts)된 값
-
clearUser() 동작 확인
- src/shared/slices/userSlice.ts 에서
user: null만 설정하도록 구현되어 있습니다. - 세션 만료 시, 사용자 정보 외에도 TanStack Query 캐시가 남아 있을 수 있으므로
queryClient.removeQueries(['user', 'me'])또는queryClient.clear()등을 통해 추가 초기화를 고려해주세요.
- src/shared/slices/userSlice.ts 에서
-
기타 에러 코드 검토
- 401 외에, 403(권한 없음) 등 다른 HTTP 상태에서도 UX 방어 로직(리다이렉트·상태 초기화)이 필요한지 함께 검토 바랍니다.
– 검사 대상
- src/app/_components/ClientProvider.tsx (useEffect 내
clearUser()호출부) - 필요 시 queryClient 초기화 로직 추가 위치
🤖 Prompt for AI Agents
In src/app/_components/ClientProvider.tsx around lines 33 to 40, the current
session expiration handling calls clearUser() but does not clear TanStack Query
cache, which may leave stale data. To fix this, import and use the queryClient
instance to call queryClient.removeQueries(['user', 'me']) or
queryClient.clear() inside the useEffect when the session expired error is
detected, ensuring all relevant cached data is cleared. Also, review if similar
handling is needed for other error codes like 403 and implement corresponding
state resets or redirects as appropriate.
9ae91a3 to
7049cb8
Compare
….com/codeit-FE-15-Part4-Team1/RoamReady into feat/541/mypage-header-image-preview
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
src/app/layout.tsx (1)
33-35: Suspense 래퍼 추가를 승인하지만 fallback 프롭 고려해보세요.ClientProvider를 Suspense로 감싸는 것은 useSearchParams() 사용으로 인한 hydration 불일치 문제를 해결하는 좋은 접근입니다. 하지만 fallback 프롭이 없어서 suspending 중에는 아무것도 표시되지 않습니다.
로딩 상태를 개선하려면 다음과 같이 fallback을 추가하는 것을 고려해보세요:
- <Suspense> + <Suspense fallback={<div>Loading...</div>}> <ClientProvider>{children}</ClientProvider> </Suspense>
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
src/app/layout.tsx(2 hunks)src/domain/Auth/utils/setAuthCookies.ts(2 hunks)src/shared/libs/formatErrorResponseHooks.ts(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- src/domain/Auth/utils/setAuthCookies.ts
- src/shared/libs/formatErrorResponseHooks.ts
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/app/layout.tsx (1)
src/app/_components/ClientProvider.tsx (1)
ClientProvider(32-49)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: vercel-preview
🔇 Additional comments (1)
src/app/layout.tsx (1)
5-5: Suspense import 추가가 적절합니다.Suspense 컴포넌트 사용을 위한 import가 올바르게 추가되었습니다.
👻 관련 이슈 번호
👻 요약
클라이언트 애플리케이션의 인증 상태 관리, 데이터 캐싱, 그리고 세션 만료 처리를 더욱 효율적이고 안정적으로 만들기 위한 리팩토링 및 신규 컴포넌트 추가
👻 주요 변경 사항
src/app/_components/ClientProvider.tsx 신규 추가
src/app/_components/AuthInitializer.tsx 신규 추가
src/app/layout.tsx 수정
src/middleware.ts 수정
src/shared/libs/formatErrorResponseHooks.ts 수정
👻 체크리스트
📷 UI 변경 사항
👻 문제 사항
👻 논의 사항
👻 기타 참고 사항
Summary by CodeRabbit
버그 수정
리팩터
스타일/구조
기타