Middleware

πŸ“˜ Express 미듀웨어 완전정볡 β€” MVCμ—μ„œμ˜ μœ„μΉ˜μ™€ μ—­ν• κΉŒμ§€

βœ… λ―Έλ“€μ›¨μ–΄λž€?

미듀웨어(Middleware)λŠ” ν΄λΌμ΄μ–ΈνŠΈμ˜ μš”μ²­(req)이 Controller에 λ„λ‹¬ν•˜κΈ° μ „ λ˜λŠ” 응닡(res)을 보내기 전에
κ³΅ν†΅μ μœΌλ‘œ μ²˜λ¦¬ν•΄μ•Ό ν•  μž‘μ—…μ„ κ°€λ‘œμ±„μ„œ μˆ˜ν–‰ν•˜λŠ” ν•¨μˆ˜μž…λ‹ˆλ‹€.

πŸ”„ λ―Έλ“€μ›¨μ–΄μ˜ μ‹€μ œ 예

미듀웨어 λͺ©μ  μ˜ˆμ‹œ ν•¨μˆ˜ 이름 μ„€λͺ…
인증 auth.js JWT 토큰이 μœ νš¨ν•œμ§€ 검사
μœ νš¨μ„± 검사 validator.js req.body의 κ°’ 체크
μ—λŸ¬ 핸듀링 error.js λͺ¨λ“  였λ₯˜λ₯Ό ν•œ κ³³μ—μ„œ 처리
λ‘œκΉ… logger.js μš”μ²­ μ‹œκ°„, 경둜 기둝

πŸ’‘ λ―Έλ“€μ›¨μ–΄λŠ” MVC 어디에 μ†ν• κΉŒ?

βœ… λ―Έλ“€μ›¨μ–΄λŠ” MVC의 핡심 계측(Model, View, Controller) μ•ˆμ—λŠ” μ†ν•˜μ§€ μ•Šμ§€λ§Œ,
Controller μ•žλ‹¨μ—μ„œ λ™μž‘ν•˜λŠ” 보쑰 계측 (Pre-controller Layer) 역할을 ν•©λ‹ˆλ‹€.

❗ Controller μ•žλ‹¨μ—μ„œ μš”μ²­μ„ κ±ΈλŸ¬λ‚΄κ±°λ‚˜ κ°€κ³΅ν•˜λŠ” μ—­ν• 
❗ Viewλ‚˜ Modelκ³ΌλŠ” 직접적인 κ΄€κ³„λŠ” μ—†μŒ

[μ‚¬μš©μž μš”μ²­]
   ⬇
[πŸ›‘ 미듀웨어 (Middleware)]
   ⬇
[🧠 컨트둀러 (Controller)]
   ⬇
[πŸ’Ύ λͺ¨λΈ (Model)]
   ⬇
[응닡 λ°˜ν™˜]

πŸ“ Express MVC + Middleware 폴더 ꡬ쑰

book-shop/
β”œβ”€β”€ app.js
β”œβ”€β”€ routes/
β”‚   └── users.js        // URL μ •μ˜ + 미듀웨어 μ—°κ²°
β”œβ”€β”€ controllers/
β”‚   └── UserController.js
β”œβ”€β”€ middlewares/
β”‚   β”œβ”€β”€ auth.js         // JWT 인증
β”‚   β”œβ”€β”€ validator.js    // μœ νš¨μ„± 검사
β”‚   └── errorHandler.js // 곡톡 μ—λŸ¬ 처리
β”œβ”€β”€ models/
β”‚   └── User.js

πŸ§ͺ 미듀웨어 μ½”λ“œ μ˜ˆμ‹œ

routes/users.js

const express = require('express');
const router = express.Router();
const auth = require('../middlewares/auth');
const UserController = require('../controllers/UserController');

router.get('/mypage', auth, UserController.getMyPage);

middlewares/auth.js

module.exports = (req, res, next) => {
  const token = req.cookies.token;
  if (!token) return res.status(401).json({ message: '둜그인 ν•„μš”' });

  try {
    const decoded = jwt.verify(token, process.env.PRIVATE_KEY);
    req.user = decoded;
    next(); // λ‹€μŒμœΌλ‘œ
  } catch (err) {
    res.status(403).json({ message: 'μœ νš¨ν•˜μ§€ μ•Šμ€ 토큰' });
  }
};

🚨 μ£Όμ˜ν•  점

β€’ λ―Έλ“€μ›¨μ–΄λŠ” λ°˜λ“œμ‹œ next()λ₯Ό ν˜ΈμΆœν•΄μ•Ό λ‹€μŒ λ―Έλ“€μ›¨μ–΄λ‚˜ 컨트둀러둜 λ„˜μ–΄κ°
β€’ express.json()처럼 μ „μ—­μ—μ„œ κ°€μž₯ λ¨Όμ € μ μš©λ˜μ–΄μ•Ό ν•˜λŠ” 미듀웨어도 쑴재

✳️ Custom Middleware λ§Œλ“€κΈ°

// middlewares/logger.js
module.exports = (req, res, next) => {
  console.log(`[${new Date().toISOString()}] ${req.method} ${req.originalUrl}`);
  next();
};

μ‚¬μš© μ˜ˆμ‹œ (app.js):

const express = require('express');
const logger = require('./middlewares/logger');

const app = express();
app.use(logger); // μ „μ—­μœΌλ‘œ 적용

🧭 μ „μ—­ vs κ°œλ³„ 미듀웨어

// μ „μ—­ 적용
app.use(express.json());

// κ°œλ³„ 적용
router.post('/join', validateUser, UserController.join);

🚨 μ—λŸ¬ 핸듀링 미듀웨어

// middlewares/errorHandler.js
module.exports = (err, req, res, next) => {
  console.error(err.stack);
  res.status(500).json({ message: 'μ„œλ²„ λ‚΄λΆ€ 였λ₯˜ λ°œμƒ' });
};

μ‚¬μš© μ˜ˆμ‹œ (app.js):

app.use(require('./middlewares/errorHandler'));
  • λ§ˆμ§€λ§‰ app.use()둜 등둝해야 함 (κΈ°λ³Έ λΌμš°ν„° 이후)

βœ… 정리

ν•­λͺ© μ„€λͺ…
μ—­ν•  Controller μ „Β·ν›„ 곡톡 μž‘μ—… 처리 (μ „μ²˜λ¦¬κΈ°)
μ „μ—­ vs κ°œλ³„ ꡬ뢄 λͺ¨λ“  λΌμš°ν„°μ— 적용 vs 일뢀 λΌμš°ν„°μ—λ§Œ 적용
μ˜ˆμ‹œ 인증, μœ νš¨μ„± 체크, 둜그, μ—λŸ¬ 핸듀링 λ“±
MVC λ‚΄ μœ„μΉ˜ Controller κ³„μΈ΅μ˜ 보쑰 κ³„μΈ΅μœΌλ‘œ, ꡬ쑰 μ™Έκ³½μ—μ„œ λ™μž‘

미듀웨어λ₯Ό 잘 ν™œμš©ν•˜λ©΄ λ³΅μž‘ν•œ λ‘œμ§μ„ Controllerμ—μ„œ λΆ„λ¦¬ν•˜μ—¬
μš”μ²­ 흐름을 κΉ¨λ—ν•˜κ²Œ μ •λ¦¬ν•˜κ³ , 쀑볡을 μ€„μ΄λŠ” 핡심 μš”μ†Œμž…λ‹ˆλ‹€.
잘 μͺΌκ°œμ„œ μ μš©ν•˜λ©΄ μ½”λ“œ 가독성, μœ μ§€λ³΄μˆ˜μ„±, ν™•μž₯μ„± λͺ¨λ‘ μ’‹μ•„μ§‘λ‹ˆλ‹€.