Next.js 에러 핸들링: 안정적인 애플리케이션 만들기

작성일 :

Next.js 에러 핸들링: 안정적인 애플리케이션 만들기

Next.js는 React 애플리케이션을 위한 강력한 프레임워크로, 서버 사이드 렌더링(SSR)과 정적 사이트 생성(SSG)을 안정적으로 지원합니다. 하지만 아무리 잘 짜여진 코드라고 할지라도 에러는 발생할 수 있기 때문에, 다양한 에러를 효과적으로 처리하는 것은 안정적이고 사용자 경험이 뛰어난 애플리케이션을 만드는 데 필수적입니다. 이번 글에서는 Next.js에서 에러를 효율적으로 핸들링하는 방법을 다루겠습니다.

1. 에러 타입 이해하기

Next.js에서 발생할 수 있는 에러는 크게 세 가지로 분류할 수 있습니다: 컴파일 에러, 런타임 에러, 서버 에러입니다.

컴파일 에러

컴파일 에러는 애플리케이션 코드 작성 중 문법적인 오류나 컴파일러가 감지한 오류입니다. 이러한 에러는 개발 단계에서 Visual Studio Code(VSCode)나 WebStorm 같은 코드 에디터와 연동된 Linter를 통해 즉시 확인할 수 있습니다.

javascript
// 컴파일 에러 예시
const sum = (a, b) => {
  return a + b
}
console.log(sum(1, 2));
console.log(sum(1)); // 두 번째 인자가 빠져 있어 오류 발생

런타임 에러

런타임 에러는 애플리케이션이 실행 중에 발생하는 오류로, 함수 호출이나 API 결과 처리 등에서 발생할 수 있습니다. 이러한 에러는 try-catch 구문을 이용해 처리할 수 있습니다.

javascript
// 런타임 에러 예시
try {
  const response = await fetch('/api/data');
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error('Fetch error:', error);
}

서버 에러

서버 에러는 서버 측에서 발생하는 오류로, 데이터베이스 연결 실패, 서버 과부하 등 다양한 원인에 의해 발생할 수 있습니다. 이러한 오류는 서버 로그를 활용해 감지하고 처리를 해야 합니다.

2. 커스텀 에러 페이지 만들기

Next.js는 기본적으로 사용자에게 에러 페이지를 제공합니다. 하지만 커스텀 에러 페이지를 만들면 사용자 경험을 개선하고, 브랜드 일관성을 유지할 수 있습니다. pages/_error.js 파일을 생성해 커스텀 에러 페이지를 만들 수 있습니다.

javascript
// pages/_error.js
import React from 'react';

const ErrorPage = ({ statusCode }) => {
  return (
    <p>
      {statusCode
        ? `An error ${statusCode} occurred on server`
        : 'An error occurred on client'}
    </p>
  );
}

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

export default ErrorPage;

3. 전역 에러 핸들링

서버 측 에러를 전역적으로 핸들링하기 위해 getInitialProps를 활용할 수 있습니다. 이 메서드를 이용하여, 페이지가 요청될 때 에러를 감지하고 처리할 수 있습니다.

javascript
// _app.js
import App from 'next/app';
import React from 'react';

class MyApp extends App {
  static async getInitialProps({ Component, ctx }) {
    let pageProps = {};
    if (Component.getInitialProps) {
      pageProps = await Component.getInitialProps(ctx);
    }
    return { pageProps };
  }

  componentDidCatch(error, errorInfo) {
    console.error('An error occurred:', error, errorInfo);
    // logErrorToMyService(error, errorInfo);
  }

  render() {
    const { Component, pageProps } = this.props;
    return <Component {...pageProps} />;
  }
}

export default MyApp;

4. API 경로 에러 핸들링

Next.js에서 API 경로를 정의할 때도 에러 핸들링이 중요합니다. API 요청 시 발생할 수 있는 다양한 오류를 처리하여 클라이언트에 적절한 응답을 제공해야 합니다.

javascript
// pages/api/data.js
export default async (req, res) => {
  try {
    const data = await fetchDataFromDatabase();
    res.status(200).json({ data });
  } catch (error) {
    console.error('API error:', error);
    res.status(500).json({ error: 'Internal Server Error' });
  }
};

5. 사용자 정의 에러 클래스

특정 상황에서 발생하는 에러를 명시적으로 처리하기 위해 사용자 정의 에러 클래스를 활용할 수 있습니다. 이를 통해 에러 종류를 분류하고, 각 에러에 대해 다양한 처리 방식을 적용할 수 있습니다.

javascript
// errors/CustomError.js
class CustomError extends Error {
  constructor(message, statusCode) {
    super(message);
    this.statusCode = statusCode;
  }
}

export default CustomError;

이제 CustomError 클래스를 이용해 특정 상황에서 발생하는 에러를 처리할 수 있습니다.

javascript
// pages/api/custom.js
import CustomError from '../../errors/CustomError';

export default async (req, res) => {
  try {
    const data = await fetchCriticalData();
    if (!data) {
      throw new CustomError('Critical data not found', 404);
    }
    res.status(200).json({ data });
  } catch (error) {
    if (error instanceof CustomError) {
      res.status(error.statusCode).json({ error: error.message });
    } else {
      res.status(500).json({ error: 'Internal Server Error' });
    }
  }
};

결론

Next.js 에러 핸들링은 우수한 사용자 경험을 제공하고, 안정적인 애플리케이션을 만들기 위해 필수적입니다. 여러 가지 에러 상황을 명시적으로 처리하고, 커스텀 에러 페이지 및 사용자 정의 에러 클래스를 활용함으로써 예기치 못한 오류를 효과적으로 대응할 수 있습니다. 이러한 방법들을 통해 Next.js 애플리케이션을 더욱 견고하게 만들어보세요.