이번 포스팅에서는 Node.js로 기본 웹 서버를 구축하는 방법을 알아보겠습니다.
특히 이번 포스팅에서는 Middleware을 중점적으로 다루겠습니다.
앞서 Routing 포스팅([Node.js – 기초 강좌] 5-1. 기본 웹 서버 구축(Routing 편)) 역시 미들웨어(Middleware)를 사용한 것입니다.

미들웨어(Middleware) 소개
Middleware 란?
미들웨어(Middleware)는 웹 애플리케이션에서 요청(request)과 응답(response) 사이에서 동작하는 소프트웨어 컴포넌트를 의미합니다.
Node.js에서 미들웨어는 주로 Express와 같은 웹 프레임워크에서 사용되며, 각종 공통 기능을 모듈화하여 코드의 재사용성과 유지보수성을 높이는 데 기여합니다.
기본 구조
미들웨어 함수는 기본적으로 세 가지 매개변수를 받습니다:
req
(요청 객체)res
(응답 객체)next
(다음 미들웨어 함수를 호출하는 콜백 함수)
기본적인 미들웨어 함수의 형태는 다음과 같습니다:
import { Request, Response, NextFunction } from 'express'; const middlewareFunction = (req: Request, res: Response, next: NextFunction): void => { // 작업 수행 next(); // 다음 미들웨어 호출 };
미들웨어의 역할
미들웨어는 다양한 역할을 수행할 수 있습니다. 주로 다음과 같은 기능을 담당합니다:
- 요청 로깅 (Request Logging): 모든 요청에 대한 로그를 남겨 서버의 활동을 기록합니다.
- 인증 및 권한 관리 (Authentication and Authorization): 사용자가 요청한 자원에 접근할 권한이 있는지 확인합니다.
- 에러 처리 (Error Handling): 애플리케이션에서 발생하는 에러를 중앙에서 관리하고, 적절한 응답을 반환합니다.
- 데이터 파싱 (Data Parsing): 요청 본문을 파싱하여 JSON이나 URL-encoded 데이터 형식으로 변환합니다.
- 라우팅 (Routing): 요청 URL에 따라 적절한 핸들러로 요청을 전달합니다.
Middleware 사용하기
다음 위에서 설명한 Middleware를 사용해 보도록 하겠습니다.
폴더 구조
Node.js, Typescript, Express를 사용하는 환경에서 위 Middleware들을 사용할 예정이며,
다음과 같은 구조로 프로젝트를 구성할 예정입니다.
05_02_middleware/ ├── src/ │ ├── middlewares/ │ │ ├── requestLogger.ts │ │ ├── checkAuth.ts │ │ ├── errorHandler.ts │ │ ├── dataParsers.ts │ ├── routes/ │ │ └── index.ts │ ├── app.ts │ └── server.ts ├── tsconfig.json └── package.json
1. 요청 로깅 (Request Logging)
요청 로깅 미들웨어는 모든 요청에 대한 로그를 남겨 서버의 활동을 기록합니다.
이는 디버깅과 모니터링에 유용합니다.
import { NextFunction, Request, Response } from "express"; // Request logger middleware const requestLogger = ( req: Request, res: Response, next: NextFunction ): void => { console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`); next(); }; export default requestLogger;
2. 인증 및 권한 관리 (Authentication and Authorization)
인증 및 권한 관리 미들웨어는 사용자가 요청한 자원에 접근할 권한이 있는지 확인합니다.
Client가 요청 시, 인증 헤더 (Authorization
)에 포함된 req.headers.authorization
를 통해 서버는 Client가 보낸 토큰을 추출하고,
이를 검사합니다. 아래 예제에서는 Devitworld
로 시작하는지 확인하고, Devitworld
다음에 오는 실제 토큰 값을 추출하여 토큰값의 유효성을 검증합니다.
인증이 성공하면 next()
실패하면 res.status(401).json({ message: "Unauthorized" });
를 반환합니다.
import { NextFunction, Request, Response } from "express"; // Auth middleware const checkAuth = (req: Request, res: Response, next: NextFunction): void => { const authHeader = req.headers.authorization; if (authHeader && authHeader.startsWith("Devitworld ")) { const token = authHeader.split(" ")[1]; // Logic to validate token if (token === "your_valid_token") { return next(); } } res.status(401).json({ message: "Unauthorized" }); }; export default checkAuth;
- 단 실제 Application에서는 JWT를 사용하여 인증을 처리하는 경우가 많습니다.
JWT에 대한 간략한 예제는 다음과 같습니다.
import { NextFunction, Request, Response } from "express"; import jwt from "jsonwebtoken"; const SECRET_KEY = "your_secret_key"; // JWT 인증 미들웨어 const checkAuth = (req: Request, res: Response, next: NextFunction): void => { const authHeader = req.headers.authorization; if (authHeader && authHeader.startsWith("Bearer ")) { const token = authHeader.split(" ")[1]; jwt.verify(token, SECRET_KEY, (err, decoded) => { if (err) { return res.status(401).json({ message: "Unauthorized" }); } // 토큰이 유효하면 decoded에 디코딩된 정보가 담깁니다. req.user = decoded; // TypeScript에서는 req.user 타입을 선언해야 합니다. next(); }); } else { res.status(401).json({ message: "Unauthorized" }); } }; export default checkAuth;
3. 에러 처리 (Error Handling)
에러 처리 미들웨어는 애플리케이션에서 발생하는 모든 에러를 중앙에서 관리하고, 적절한 응답을 반환합니다.
import { NextFunction, Request, Response } from "express"; // error handler middleware const errorHandler = ( err: Error, req: Request, res: Response, next: NextFunction ): void => { console.error(err.stack); res.status(500).json({ message: "Something broke!", error: err.message }); }; export default errorHandler;
4. 데이터 파싱 (Data Parsing)
데이터 파싱 미들웨어는 요청 본문을 파싱하여 JSON이나 URL-encoded 데이터 형식으로 변환합니다.
import express from "express"; // JSON Parser Middleware const jsonParser = express.json(); // URL-encoded Parser Middleware const urlEncodedParser = express.urlencoded({ extended: true }); export { jsonParser, urlEncodedParser };
5. 라우팅 (Routing)
라우팅 미들웨어는 요청 URL에 따라 적절한 핸들러로 요청을 전달합니다.
라우팅 미들웨어에 대해서는 앞선 포스팅에서 자세히 소개했습니다.
import { Request, Response, Router } from "express"; const router = Router(); // Basic route router.get("/", (req: Request, res: Response) => { res.send("Hello, World!"); }); router.get("/secure/data", (req: Request, res: Response) => { res.send("Secure data"); }); export default router;
참고 링크
- Express 공식 페이지
- devitworld nodejs tutorial repository
- https://github.com/jh4843/devitworld-nodejs-basic/05_02_middlware