관련 공식 문서 : 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
파일을 별도로 둠