관련 공식 문서 : https://nextjs.org/docs/app/api-reference/functions/redirect
customFetch 함수 : 로그인할 때 로컬 스토리지에 저장해 놓은 토큰 값을 기본 헤더로 포함하고, API 요청 BASE_URL을 추가해서 fetch 요청 후 Response를 반환 -> Response의 status가 401이면 로그인 페이지로 redirect 함
[초기 구현 코드]
export async function customFetch(
requestURL: string,
options?: RequestInit
): Promise<Response> {
const headers = { ...defaultHeaders, ...options?.headers };
const mergedURL = BASE_URL + requestURL;
const mergedOptions = { ...options, headers };
const response = await fetch(mergedURL, mergedOptions);
if (response.status === 401) {
redirect('/login');
}
return response;
}
-> Error: NEXT_REDIRECT at getRedirectError
next.js 깃허브 리포지토리에 남겨진 이슈와 스택 오버플로우를 참고해서 수정해보았지만 거의 해결이 되지 않음
[수정 코드]
export async function customFetch(
requestURL: string,
options?: RequestInit
): Promise<Response> {
const headers = { ...defaultHeaders, ...options?.headers };
const mergedURL = BASE_URL + requestURL;
const mergedOptions = { ...options, headers };
const response = await fetch(mergedURL, mergedOptions);
if (response.status === 401) {
window.location.replace('/login');
}
return response;
}
/* redirect.d.ts */
export declare function getRedirectError(url: string, type: RedirectType): RedirectError<typeof url>;
/**
* When used in a React server component, this will insert a meta tag to
* redirect the user to the target page. When used in a custom app route, it
* will serve a 302 to the caller.
*
* @param url the url to redirect to
*/
export declare function redirect(url: string, type?: RedirectType): never;
/**
* Checks an error to determine if it's an error generated by the
* `redirect(url)` helper.
*
* @param error the error that may reference a redirect error
* @returns true if the error is a redirect error
*/
export declare function isRedirectError<U extends string>(error: any): error is RedirectError<U>;
/**
* Returns the encoded URL from the error if it's a RedirectError, null
* otherwise. Note that this does not validate the URL returned.
*
* @param error the error that may be a redirect error
* @return the url if the error was a redirect error
*/
![]()
Next.js 공식 문서와 redirect() 정의를 보면 redirect()가 NEXT_REDIRECT 에러를 발생시키는 것은 맞으나 사용 예제를 보면 올바르게 사용한 것 같은데 문제가 되는 이유를 고민해보았다.
그러다 layout.tsx 파일에 로컬 스토리지에서 토큰 값을 읽어왔을 때 null이면 로그인 페이지로 redirect 되도록 redirect('/login');을 코드를 작성했는데 정상적으로 로그인 페이지로 redirect 되는 것을 확인하게 되었다.
![]()
확실하지는 않지만 Next.js 공식 문서에 서버 컴포넌트, 클라이언트 컴포넌트, 라우트 핸들러, Server Actions에 사용될 수 있다고 적혀있는데 내가 작성한 customFetch 함수는 여기에 속하지 않아서 그렇지 않을까라고 추측해 보았다.
그러나 이 이유가 확실한지는 확인이 필요할 것 같다.
위에 작성한 layout.tsx 파일의 로컬 스토리지에서 토큰 값을 읽어왔을 때 null이면 로그인 페이지로 redirect 되도록 하는 redirect('/login');코드
로그인 없이 메인 페이지로 바로 접속하자 로그인 페이지로 redirect가 되었으나 리다이렉션한 횟수가 너무 많습니다 라는 에러가 발생하였다.
-> 해결하기 위해 쿠키 삭제도 해보았으나 해결되지 않음
원인
: 작성한 layout.tsx이 app 디렉토리 안에 바로 있는 가장 상위의 layout 파일이어서 로그인 페이지에서도 적용되는 파일임 -> 로그인 페이지로 redirect 된 이후에도 세션 스토리지에 토큰이 없어 로그인 페이지로 무한대로 redirect가 됨
해결
: Route Group(https://nextjs.org/docs/app/building-your-application/routing/route-groups)을 사용해서 (auth) 디렉토리와 (service) 디렉토리를 구분한 후 layout.tsx 파일을 별도로 둠
엄청나게 늦은 감이 없지 않아 있지만... 원인을 알려드리자면 Next.js에서는 error를 통해 특정 동작을 처리합니다. 그중 하나가 redirect로 error의 digest를 분석하면 url과 https 코드, 동작 유형등이 적혀 있어요. 그래서 redirect 함수는 단지 에러를 던지는 것 뿐인데 이걸 커스텀 함수에서 try catch 구문으로 에러를 핸들링하려하면 해당 구문에서 에러를 감지해서 문제를 일으킵니다.