컴포넌트 Fetch 에러 (2)
작성일: 2025.01.04
배경
Next.js에서 서버 컴포넌트와 클라이언트 컴포넌트의 fetch 동작 방식이 다르다는 것을 발견했습니다. 처음에는 단순히 serverFetch와 같은 별도의 함수를 만들어 해결하려 했으나, 이는 개발자가 컴포넌트의 유형에 따라 다른 함수를 사용해야 하는 불편함이 있었습니다.
이에 서버와 클라이언트 환경을 자동으로 감지하고, 각 환경에 맞는 처리를 수행하는 통합 fetch 유틸리티를 개발하게 되었습니다.
1. 기본 개념
서버 컴포넌트와 클라이언트 컴포넌트의 차이
- 서버 컴포넌트: Node.js 환경에서 실행, rewrites 설정 미적용
- 클라이언트 컴포넌트: 브라우저에서 실행, rewrites 설정 적용
fetch 요청 처리의 차이
- 서버 컴포넌트: 전체 URL 필요, 쿠키/헤더 수동 처리 필요
- 클라이언트 컴포넌트: 상대 경로 사용 가능, 브라우저가 자동으로 쿠키/헤더 처리
2. 실제 해결 방안
환경 분리를 통한 URL 처리
const getURL = () => {
// 프로덕션 + 서버사이드
if (process.env.NODE_ENV === 'production' && isServer) {
return 'http://localhost:8080';
}
// 개발환경 + 클라이언트사이드
if (process.env.NODE_ENV === 'development' && !isServer) {
return '';
}
// 기타 환경
return API_URL;
};
쿠키 처리
export const FetchWithCookie = async (
input: RequestInfo | URL,
init?: RequestInit
) => {
// 프로덕션 서버사이드에서만 수동으로 쿠키 처리
if (process.env.NODE_ENV === 'production' && isServer) {
const cookies = await getServerCookies();
const cookieString = cookies().toString();
return Fetch(input, {
...init,
headers: {
...init?.headers,
'Content-Type': 'application/json',
Cookie: cookieString,
},
credentials: 'include',
});
}
// 그 외 환경에서는 기본 처리
return Fetch(input, {
...init,
credentials: 'include',
});
};
JWT 토큰 재발급 처리
export const FetchWithJWT = async (
input: RequestInfo | URL,
init?: RequestInit
) => {
const res = await FetchWithCookie(input, init);
// 401 에러 시 토큰 재발급
if (res.status === 401) {
const tokensRequest = await fetch('/api/reissue', init);
if (!tokensRequest.ok) return tokensRequest;
// 프로덕션 서버사이드에서 새 쿠키 설정
if (process.env.NODE_ENV === 'production' && isServer) {
const cookies = await getServerCookies();
const newCookies = tokensRequest.headers.getSetCookie();
newCookies.forEach((cookie) => {
const [name, value] = cookie.split('=');
cookies().set(name, value);
});
}
return FetchWithCookie(input, init);
}
return res;
};
3. 주요 포인트
환경별 처리가 필요한 이유
-
프로덕션 서버사이드
- 직접 API 서버 호출 필요
- 쿠키/헤더 수동 처리 필요
- rewrites 설정 적용 안됨
-
개발환경 클라이언트사이드
- rewrites 설정 활용 가능
- 브라우저가 자동으로 쿠키/헤더 처리
- 상대 경로 사용 가능
핵심 고려사항
-
URL 처리
- 환경에 따른 적절한 URL 선택
- rewrites 설정 활용 여부 결정
-
인증 처리
- 쿠키 자동/수동 처리
- JWT 토큰 재발급 로직
- 환경별 쿠키 설정 방식
-
에러 처리
- 401 에러 시 토큰 재발급
- 쿠키 획득 실패 시 폴백 처리
4. 결론
Next.js에서 fetch를 올바르게 처리하기 위해서는:
- 서버/클라이언트 환경의 차이 이해
- 환경별 적절한 URL 처리 방식 선택
- 인증과 쿠키 처리의 자동화
- 에러 상황에 대한 적절한 대응
이러한 요소들을 모두 고려한 fetch 유틸리티를 만들면, 서버와 클라이언트 모두에서 안정적으로 작동하는 API 호출이 가능합니다.