📢 어렵고 정석적인 개념 설명보다는 저같은 초보자도 이해하기 쉽게 정리하는 것을 원칙으로 포스팅하고 있습니다. 😄

[Next.js] 에러 페이지 만들기 (404, 500, notFound, error)

Next.js에서 에러 페이지란?

Next.js에서 에러 페이지는 웹 어플리케이션에서 발생하는 오류 상황을 사용자에게 효과적으로 전달하기 위해 설계된 페이지이다. 예를 들어, 없는 페이지의 경로로 접속하거나(404), 서버에서 예상치 못한 오류가 발생할 때(500) 이 페이지가 사용된다. 또한, API 요청이 실패하거나 데이터 처리 중 오류가 발생하는 등 런타임 과정에서 에러가 발생했을 때 사용자들에게 오류를 알리는 페이지이다. 이것은 개발자가 오류 상황을 효과적으로 관리하고, 사용자에게 오류가 발생했으니 어떤 행동을 취하라는 식의 적절한 피드백을 줄 수 있도록 돕는 역할을 수행한다.

 

에러 페이지 만들기 : Page Router

// 404.tsx
export default function Custom404() {
    return (
        <div>
            <h1>404 - 페이지를 찾을 수 없습니다.</h1>
            <p>잘못된 경로로 접근하셨습니다.</p>
        </div>
    );
};

// _error.tsx
function Error({ statusCode }) {
    return (
        <div>
            <h1>{statusCode} 오류가 발생하였습니다.</h1>
        </div>
    )
}

Error.getInitialProps = ({ res, err }) => {
    const statusCode = res ? res.statusCode : err ? err.statusCode : 404;
    return { statusCode };
}

export default Error;

Next.js의 페이지 라우터에서는 404.tsx, 500.tsx, _error.tsx 등을 사용하여 에러 페이지를 구현한다. 404.tsx, 500.tsx는 각각 404, 500 오류가 발생했을 때 전용으로 처리하는 페이지이다. 예를 들어, 페이지를 찾을 수 없는 경우에는 404.tsx가, 서버에서 오류가 발생하면 500.tsx가 실행된다.

 

_error.tsx는 모든 HTTP 오류를 처리하는 전역 에러 페이지이다. 즉, 404, 500 이외의 다른 오류들도 이 페이지에서 처리된다. 만약 404.tsx와 _error.tsx가 동시에 존재할 경우, 404 오류는 _error.tsx가 아닌 404.tsx에서 우선적으로 처리된다.

 

에러 페이지 만들기 : App Router

// not-found.tsx
export default function NotFound() {
    return <div>404 Not Found</div>
}

// notFound() 함수
import { notFound } from 'next/navigation';

export default async function PostPage({ params }) {
    const post = await fetch(params.id);

    if (!post) {
        notFound(); // notFound 페이지로 보내버리기
    }

    return (
        <div>{post.title}</div>
    )
}

페이지 라우터에서는 404.tsx로 404 오류를 처리했지만, 앱 라우터에서는 not-found.tsx를 사용한다. 또한, notFound()라는 내장 메서드를 호출하여 특정 조건에서 오류 페이지로 리다이렉트할 수도 있다.

 

// error.tsx
"use client";

export default function Error({ error, reset }: { error: Error; reset: () => void }) {
    return (
        <div>
            <h1>오류가 발생했습니다.</h1>
            <p>{error.message || '서버에서 오류가 발생했습니다.'}</p>
            <button onClick={() => reset()}>다시 시도하기</button>
        </div>
    )
}

앱 라우터에서 에러 처리는 주로 error.tsx에서 이루어진다. error.tsx는 런타임 과정에서 발생하는 오류를 처리하며, try-catch 문에서 catch문에 throw Error() 부분을 담당한다고 생각하면 된다. (API 요청 실패나 데이터베이스 연결 오류, 컴포넌트 렌더링 오류, 500과 같은 서버 측 오류 등 코드가 실행되는 과정 중 발생하는 모든 오류를 처리한다.)

 

페이지 라우터_error.tsx가 모든 HTTP 오류를 처리하는 전역 에러 페이지였다면, 앱 라우터error.tsx는 런타임 오류를 처리하며, 각 페이지나 레이아웃에서 발생하는 오류를 처리한다. 앱 라우터에서 404 오류는 not-found.tsx에서 따로 처리되므로, error.tsx는 500과 같은 런타임 오류를 처리하거나 특정 레이아웃에서만 발생하는 오류를 처리할 수 있다. 물론 최상위에 위치시켜서 전역 에러 페이지로도 사용할 수 있다.

 

error.tsx는 클라이언트 컴포넌트로 선언되어야 하는데, 이는 서버뿐만 아니라 클라이언트 측 오류도 처리해야 하기 때문이다. 따라서 "use client" 지시어를 사용하여 클라이언트 컴포넌트로 설정함으로써 클라이언트와 서버에서 발생하는 오류를 모두 처리할 수 있다.

🤔 Next.js에서 런타임이란?
서버에서 발생하는 코드(서버 측에서 데이터 요청, 렌더링 등)와 클라이언트에서 발생하는 코드(초기 렌더링, 하이드레이션, 추가 API 호출 등) 모두를 포함하는 개념으로 페이지를 만드는 과정 전부를 런타임 과정이라고 한다. (빌드 타임을 제외한 페이지 제작에 있어 모든 과정(서버 + 클라이언트)이라고 생각하면 된다.)
1. 페이지 라우터에서 에러 핸들링 : _error.tsx(모든 오류), 404.tsx(404 오류), 500.tsx(500 오류)
2. 앱 라우터에서의 에러 핸들링 : error.tsx(런타임 오류), not-found.tsx(404 오류)