노드JS 미들웨어(1) 기본
미들웨어
미들웨어는 Express 모듈의 핵심이다.
Node.js에서 미들웨어는 클라이언트의 요청과 서버의 응답 사이에서 동작하는 함수이다.
app.use(미들웨어);
app.use
안에 있는 모든 함수들은 모두 미들웨어이며 요청이 올때마다 이 미들웨어를 거친다. 즉, 요청과 응답의 중간(middle, 미들)에 위치하여 미들웨어 라고 부른다.
미들웨어는 요청과 응답을 조작하여 기능을 추가하기도 하고, 나쁜 요청을 걸러내기도 한다.
미들웨어 처리 과정
- 미들웨어는 요청과 응답을 조작하고,
- 다음 미들웨어를 호출하고,
- 요청을 처리하는 핵심 애플리케이션 로직에 접근할 수 있다. (next)
미들웨어 구조
미들웨어는 req, res, next와 같은 매개변수를 받아서 작동한다.
구조
// function 부분이 미들웨어 이다.
app.use(function(req, res, next) {
// 미들웨어 처리 로직
next();
});
즉, app.use에 매개변수가 req, res, next인 함수를 넣으면 된다.
여기서 미들웨어는 next 인자가 들어있다는 점이 특징이다.
- req: HTTP 요청 객체.
- res: HTTP 응답 객체
- next: 다음 미들웨어를 호출하는 함수. 미들웨어는 next 함수를 호출하지 않으면 다음 미들웨어를 실행하지 않는다
미들웨어 사용
주소를 첫 번째 인수로 넣어주지 않는다면 미들웨어는 모든 요청에서 실행되고, 주소를 넣는다면, 해당하는 요청에서만 실행됩니다.
Express 함수 | 내용 |
---|---|
app.use(미들웨어) | 모든 요청에서 해당 미들웨어 실행 |
app.use(/경로, 미들웨어) | path로 시작하는 요청에서 미들웨어 실행 |
app.get(/경로, 미들웨어) | path로 시작하는 GET 요청에서 미들웨어 실행 |
app.post(/경로, 미들웨어) | path로 시작하는 POST 요청에서 미들웨어 실행 |
출처) 바로가기
미들웨어 동작
- 클라이언트가 서버로 요청을 보낸다.
- 요청이 Express 애플리케이션에 도착하면, 등록한 미들웨어 함수들이 먼저 차례대로 실행된다.
- 모든 미들웨어 함수의 처리가 완료되면, 요청을 처리할 수 있는 라우트 핸들러가 실행된다.
- 라우트 핸들러가 응답(response)을 반환하면, 응답 객체가 클라이언트로 전송 된다.
const express = require('express');
const cors = require('cors'); // cors 미들웨어 임포트
const app = express();
// CASE1: 모듈 미들웨어 (이미 구현된 cors 라는 모듈의 미들웨어)
// app.use가 미들웨어가 아니라 app.use()의 인자안의 함수가 미들웨어임.
app.use(cors());
// CASE2: 사용자정의 미들웨어
app.use((req, res, next) => { // 로그를 찍는 용도의 미들웨어
console.log('first');
next();
});
// CASE3: 모듈 미들웨어 (라우트 핸들러 미들웨어)
// app.get이 미들웨어가 아니라 app.get()의 인자안의 함수가 미들웨어임.
app.get('/', (req, res) => {
res.send('Hello, World!');
});
위 코드에서는 총 3개의 미들웨어를 구현하고있다.
- cros 미들웨어
- 로그를 찍는 미들웨어
- 라우터핸들러 미들웨어
이제 라우터 요청을 수행하기 전에 등록한 미들웨어가 동작하게 된다. 마치 스프링의 AOP 미들웨어를 구현한 느낌이다..!
미들웨어 구현 예제
# 미들웨어 관리 폴더를 생성하고 작업한다.
mkdir middlewares
cd middlewares
로그 찍는 미들웨어 모듈 만들기
/middlewares/logger.js
const logger = () => (req, res, next) => {
const log = `${req.method} ${req.url}`
console.log(log)
next()
}
module.exports = logger
/app.js
const express = require('express');
const app = express();
// 미들웨어 Import
const logger = require('./middlewares/logger');
// 미들웨어 등록
app.use(logger())
// 서버 실행
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
# 접속 /about
GET /about
# 접속 /product
GET /product
# 접속 /admin
GET /admin
Express의 에러처리 미들웨어
에러 핸들링을 위한 미들웨어어 알아본다. Express에서 제공하는 next 함수의 인자로 에러 객체를 전달하면, 에러 핸들러 미들웨어에서 처리할 수 있다.
/app.js
const express = require('express');
const app = express();
// (라우트 핸들러 미들웨어)
app.get('/', (req, res) => {
res.send('Hello, World!');
});
// (에러처리 미들웨어)
// 1. 맨앞 err을 포함한 인자 4개를 가지는 특징이 있다.
// 2. 라우터 미들웨어보다 뒤에있는 특징이 있다.
app.use((err, req, res, next) => {
console.error(err); // 에러 로그를 출력
res.status(500).send('Something broke!'); // 에러 응답을 전송
});
app.get('/errRun', (req, res) => {
console.log('의도한 익셉션 수행');
throw new Error('에러는 에러 처리 미들웨어로 갑니다.');
});
// 서버 실행
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
Express에서 에러 처리 미들웨어는 4개의 인자로 오버로딩
되어 구현되어있다.
이 미들웨어의 특이한 점은 next() 함수를 호출하지 않아도 된다. 이는 다른 미들웨어와 달리, 요청 처리 결과에 영향을 미치지 않는 특수한 미들웨어이기 때문이다.
- app.use를 사용하여 등록 한다.
- 첫 번째 인자를 err(에러) 객체로 하여 총 4개의 인자를 부여 해야한다.
- 특수한 미들웨어라서 일반적으로, 모든 미들웨어 다음줄
code line
에 등록하며, 요청 처리 중 발생하는 에러를 처리한다. 아래는 호출되는 예시다.- next(err) 함수를 호출한 경우
// 실제 미들웨어 내용을 까보면 아래 내용이 구현되어 있을것이다. try { // .. 에러 발생 코드 } catch(err) { error(err); // next()에 인수가 있다면, 에러 처리 미들웨어로 점프한다. }
- 라우터 함수나 미들웨어 함수 내부에서 에러가 발생한 경우
- next(err) 함수를 호출한 경우
- 에러가 발생한 경우 이후의 미들웨어는 실행되지 않고, 바로 에러 처리 미들웨어로 전달 된다.
- /errRun 을 요청해보면 결과는 다음과 같다.
의도한 익셉션 수행 Error: 에러는 에러 처리 미들웨어로 갑니다. at /fswas/wasadm/nodeStudy/app_temp.js:19:10 at Layer.handle [as handle_request] (/fswas/wasadm/nodeStudy/node_modules/express/lib/router/layer.js:95:5) at next (/fswas/wasadm/nodeStudy/node_modules/express/lib/router/route.js:144:13) at Route.dispatch (/fswas/wasadm/nodeStudy/node_modules/express/lib/router/route.js:114:3) at Layer.handle [as handle_request] (/fswas/wasadm/nodeStudy/node_modules/express/lib/router/layer.js:95:5) at /fswas/wasadm/nodeStudy/node_modules/express/lib/router/index.js:284:15 at Function.process_params (/fswas/wasadm/nodeStudy/node_modules/express/lib/router/index.js:346:12) at next (/fswas/wasadm/nodeStudy/node_modules/express/lib/router/index.js:280:10) at Layer.handle [as handle_request] (/fswas/wasadm/nodeStudy/node_modules/express/lib/router/layer.js:91:12) at trim_prefix (/fswas/wasadm/nodeStudy/node_modules/express/lib/router/index.js:328:13)
- /errRun 을 요청해보면 결과는 다음과 같다.
라우터 미들웨어
const express = require('express');
const app = express();
const router = express.Router();
// 라우터 미들웨어 등록
//이 미들웨어는 router.get() 함수로 등록된 라우트 핸들러가 실행되기 전에 항상 실행
router.use((req, res, next) => {
console.log('Router middleware executed.');
next();
});
/* 라우트 핸들러 등록
* WAS 설정에서 docBase 설정과 동일해보인다.
*/
router.get('/co', (req, res) => {
res.send('Hello, router!');
});
/* 라우터 등록
* WAS 설정에서 ContextPath 설정과 동일해보인다. (만약 /router 경로 요청이 오면)
*/
app.use('/router', router);
// 기본 라우트 핸들러 등록
app.get('/', (req, res) => {
res.send('Hello, world!');
});
app.listen(3000, () => {
console.log('Server is listening on port 3000');
});
정리
라우터 미들웨어는 더 깊게 다루어야 하므로 따로 포스팅 예정이다.
Leave a comment