SHIN STORYSHIN STORY
홈포스트C#TypeScriptNext.jsNode.js시리즈
</>SHIN STORY

sdf

탐색

  • 홈
  • 모든 포스트
  • 시리즈
  • 검색

카테고리

  • C#
  • TypeScript
  • Next.js
  • Node.js
  • 알고리즘
  • 개발 도구

© 2025 Shin Blog. All rights reserved.

GitHubRSS
목록으로
Node.js#JavaScript#Node.js#Backend

Express 미들웨어 패턴과 에러 처리

SHIN

2026년 4월 28일2분 읽기0
📚

Node.js 실전 팁 20선

20편
  1. 3Node.js Stream으로 대용량 파일 처리하기
  2. 4Worker Threads로 CPU 집약 작업 처리하기
  3. 5cluster 모듈로 멀티코어 CPU 100% 활용하기
  4. 6child_process로 외부 명령 실행하기
  5. 7fs/promises로 파일 시스템 다루기
  6. 20Node.js Event Loop 완전 정복
  7. 20Node.js path 모듈 완전 정복
  8. 20환경 변수 관리 — .env, dotenv, 그리고 검증
  9. 20EventEmitter 패턴으로 느슨한 결합 구현하기
  10. 20Node.js crypto 모듈로 해싱과 암호화 구현하기
  11. 20Node.js 메모리 누수 찾고 수정하기
  12. Express 미들웨어 패턴과 에러 처리현재
  13. 20Node.js CJS vs ESM 모듈 시스템 완전 정리
  14. 20Node.js Buffer와 인코딩 완전 가이드
  15. 20PM2로 Node.js 프로세스 관리하기
  16. 20Node.js HTTP 서버 직접 구현하기
  17. 20Node.js 성능 프로파일링 실전 가이드
  18. 20Node.js npm 스크립트 완전 활용하기
  19. 20Node.js 보안 체크리스트 10가지
  20. 20Node.js 테스팅 전략 — 단위, 통합, E2E 테스트

Express 미들웨어 패턴과 에러 처리

Express의 힘은 미들웨어 체인에 있습니다. 올바른 패턴을 이해하면 확장성 있는 API를 만들 수 있습니다.

미들웨어 기본 형태

CODE
// 일반 미들웨어: (req, res, next)
function logger(req, res, next) {
  console.log(`${req.method} ${req.path}`);
  next(); // 반드시 호출해야 체인이 이어짐
}

// 에러 미들웨어: (err, req, res, next) — 인자 4개
function errorHandler(err, req, res, next) {
  res.status(err.status || 500).json({ error: err.message });
}

팩토리 미들웨어 (클로저 활용)

CODE
// 설정 가능한 미들웨어 생성
function rateLimit({ max = 100, windowMs = 60_000 } = {}) {
  const counts = new Map();
  return (req, res, next) => {
    const key = req.ip;
    const now = Date.now();
    const entry = counts.get(key) || { count: 0, resetAt: now + windowMs };
    if (now > entry.resetAt) {
      entry.count = 0;
      entry.resetAt = now + windowMs;
    }
    entry.count++;
    counts.set(key, entry);
    if (entry.count > max) {
      return res.status(429).json({ error: 'Too Many Requests' });
    }
    next();
  };
}

app.use(rateLimit({ max: 200, windowMs: 60_000 }));

async 미들웨어 래퍼

CODE
// Express는 async 에러를 자동으로 잡지 않음
const asyncHandler = (fn) => (req, res, next) => {
  Promise.resolve(fn(req, res, next)).catch(next);
};

// 사용
app.get('/users', asyncHandler(async (req, res) => {
  const users = await db.user.findMany();
  res.json(users);
}));

글로벌 에러 핸들러

CODE
// 커스텀 에러 클래스
class AppError extends Error {
  constructor(message, statusCode = 500) {
    super(message);
    this.statusCode = statusCode;
    this.name = 'AppError';
  }
}

// 글로벌 핸들러 (반드시 마지막에 등록)
app.use((err, req, res, next) => {
  const statusCode = err.statusCode || 500;
  const isDev = process.env.NODE_ENV === 'development';

  console.error(err);

  res.status(statusCode).json({
    error: {
      message: err.message,
      ...(isDev && { stack: err.stack }),
    },
  });
});

// 사용
app.get('/post/:id', asyncHandler(async (req, res) => {
  const post = await db.post.findById(req.params.id);
  if (!post) throw new AppError('포스트를 찾을 수 없습니다', 404);
  res.json(post);
}));

라우터 모듈화

CODE
// routes/users.js
import { Router } from 'express';
const router = Router();

router.get('/', asyncHandler(getUsers));
router.post('/', validate(createUserSchema), asyncHandler(createUser));
router.get('/:id', asyncHandler(getUserById));

export default router;

// app.js
import userRoutes from './routes/users.js';
app.use('/api/users', userRoutes);

404 핸들러

CODE
// 모든 라우트 아래에 위치
app.use((req, res) => {
  res.status(404).json({ error: `${req.path} 경로를 찾을 수 없습니다` });
});
공유
S

SHIN

.NET 개발자입니다

GitHub
Node.js 메모리 누수 찾고 수정하기

이전 포스트

Node.js 메모리 누수 찾고 수정하기

다음 포스트

Node.js CJS vs ESM 모듈 시스템 완전 정리

Node.js CJS vs ESM 모듈 시스템 완전 정리

같은 카테고리 포스트

Node.js 테스팅 전략 — 단위, 통합, E2E 테스트

Node.js 테스팅 전략 — 단위, 통합, E2E 테스트

2026년 5월 6일· 2분
Node.js 보안 체크리스트 10가지

Node.js 보안 체크리스트 10가지

2026년 5월 5일· 2분
Node.js npm 스크립트 완전 활용하기

Node.js npm 스크립트 완전 활용하기

2026년 5월 4일· 1분

댓글