개인의 기록
  • 소개
  • 프로젝트
  • 글
  • 링크

© 2026 newgirok

← 글 목록

Express Error Handling — 에러를 중앙에서 처리하는 방법

2025년 1월 30일
ExpressError HandlingError Middlewarenext(err)async 에러

Express 앱이 커질수록 각 Route마다 에러를 직접 처리하면 코드가 중복되고 일관성이 깨진다. next(err)를 통해 에러를 중앙 Error Middleware로 흘려보내면 응답 형식을 한 곳에서 통제할 수 있다. 이 흐름을 구조적으로 이해하면 디버깅과 유지보수가 훨씬 쉬워진다.

Error Middleware의 구조

Express의 일반 Middleware는 인자가 3개(req, res, next)지만, Error Middleware는 반드시 4개(err, req, res, next)여야 한다. 인자 수가 정확히 4개여야 Express가 에러 핸들러로 인식한다.

Request
  │
  ▼
Route Handler ──── throw / next(err) ────► Error Middleware
  │                                              │
  ▼                                              ▼
Response (정상)                          Error Response (JSON)

Error Middleware — (err, req, res, next) 시그니처를 가진 특수 Middleware. 다른 Middleware가 next(err)를 호출할 때만 실행된다.

next(err)로 에러 전달하기

동기 코드에서는 try-catch로 에러를 잡은 뒤 next(err)에 넘긴다.

app.get('/users/:id', (req, res, next) => {
  try {
    const user = getUserById(req.params.id);
    if (!user) throw new Error('User not found');
    res.json(user);
  } catch (err) {
    next(err);
  }
});

async 라우트 처리

async 함수 안에서 발생한 에러는 자동으로 Express에 전달되지 않는다. Promise rejection을 next로 연결하는 래퍼가 필요하다.

// 유틸 래퍼
const asyncHandler = (fn: Function) =>
  (req: Request, res: Response, next: NextFunction) =>
    Promise.resolve(fn(req, res, next)).catch(next);

app.get('/posts', asyncHandler(async (req, res) => {
  const posts = await Post.findAll();
  res.json(posts);
}));

asyncHandler — async 함수의 rejected Promise를 자동으로 next(err)로 전달하는 패턴. Express 5부터는 async 라우트가 기본 지원된다.

커스텀 에러 클래스

HTTP 상태 코드를 에러 객체에 담으면 중앙 핸들러에서 분기 없이 처리할 수 있다.

class AppError extends Error {
  constructor(public message: string, public statusCode: number) {
    super(message);
    this.name = 'AppError';
  }
}

// 사용
throw new AppError('권한이 없습니다.', 403);

중앙 에러 핸들러

모든 에러가 모이는 곳. 반드시 다른 app.use 이후 마지막에 등록해야 한다.

app.use((err: AppError, req: Request, res: Response, next: NextFunction) => {
  const status = err.statusCode ?? 500;
  const message = err.message ?? 'Internal Server Error';

  console.error(`[${status}] ${message}`);

  res.status(status).json({ error: message });
});

에러 처리 방식 비교

방식장점단점
각 Route에서 직접 처리즉각적, 명시적코드 중복, 응답 형식 불일치
중앙 Error Middleware응답 형식 통일, 로깅 집중화초기 설계 필요
커스텀 에러 클래스상태 코드 포함, 타입 안전클래스 정의 추가

중앙 Error Middleware 패턴은 규모가 커질수록 이점이 뚜렷해진다. Route는 비즈니스 로직에만 집중하고, 에러 응답의 형식과 로깅은 한 곳에서 관리하는 구조가 Express 앱의 표준 설계다.

← 이전 글Express Router — 라우터를 분리하는 방법
다음 글 →Express Static File — 정적 파일을 제공하는 방법