2023. 12. 15. 01:59ㆍNode.js
데브코스 강의 중 app.use() 함수를 사용하여 express.json()(json parser)를 등록하는 것을 보고 그 원리가 궁금하여 더 공부해보았다.
1. Middleware란?
Middleware는 express.js의 핵심 개념 중 하나인데
간단히 설명하면 클라이언트의 request
와 response
사이에 존재하여 미들웨어 자신이 담당한 기능을 마친 후
다음 미들웨어 기능으로 제어권을 넘기거나 응답을 보내는 함수들이다.
app의 get, post 등 route handler function 들도 미들웨어의 한 예들이다.
app.get('/', (req, res) => {
res.json({ id: 1, 이름: 'Ashraful' });
};
또, 클라이언트의 요청 payload에서 json을 파싱하여
request
객체의 body
프로퍼티로 초기화해주는 express.json()
도 미들웨어 함수이다.
app.use(express.json());
이렇듯 route handle, 파싱, 로깅, 에러처리 등 request-response cycle 사이에서 개발자가 의도한 동작을 하는 함수들을
모두 미들웨어라고 할 수 있다.
위의 그림과 같이 미들웨어 스택에 등록된 미들웨어들이 순차적으로 실행된다.
express에서는 미들웨어들의 종류를 다섯 가지로 정의하고 있다.
- Application-level middleware
- Router-level middleware
- Error-handling middleware
- Built-in middleware
- Third-party middleware
2. Application-level middleware
applictaion-level 미들웨어는 app.use()
또는 app.METHOD()
함수들을 통해 app
객체에 바인딩한다.
const express = require('express');
const app = express();
//app.use()로 등록
app.use((req, res, next) => {
console.log('do something... ');
next();
});
//app.METHOD()로 등록
app.get('/', (req, res, next) => {
res.send('Hello World!');
});
//배열로 등록할 수도 있다.
app.use([foo, bar]);
function foo(req, res, next) {
console.log('foo...');
next();
}
function bar(req, res, next) {
console.log('bar...');
next();
}
위의 코드를 보면 next()
함수가 각 미들웨어 마지막에 호출 되어있는데next()
함수는 다음 미들웨어어 제어권을 넘겨주는 함수이기 때문에 꼭 호출해주어야한다.
3. Router-level middlware
Router-level 미들웨어는 Application-level 미들웨어와 같은 방식으로 동작하지만,
express.Router()
인스턴스에 바인딩 된다는 것이 다르다.
const express = require('express');
const app = express();
const router = express.Router();
//router.use()
router.use(function (req, res, next) {
console.log('do something...');
next();
});
//router.METHOD()
router.get('/foo', function (req, res, next) {
res.json({foo : 'foo')});
});
//라우터를 app에 마운트해준다.
app.use('/', router);
위의 코드만 보면 app에 등록하나 router에 등록하나 무슨 차이지? 라는 의문이 들 수 있다.
하지만 아래의 파일들을 보면 router.use()
와 router.METHOD()
가 왜 필요한지 알 수 있다.
user.js, post.js, index.js 세 파일이 있다고 가정하자
user.js
const express = require('express');
const router = express.Router();
router.post('/', (req, res) => {
// ....
res.send();
});
router.get('/:id', (req, res) => {
// ....
res.send();
});
module.exports = router;
post.js
const express = require('express');
const router = express.Router();
router.get('/', (req, res) => {
// ....
res.send();
});
router.post('/', (req, res) => {
// ....
res.send();
});
module.exports = router;
각 모듈 별로 각각의 라우터 인스턴스를 생성하고 미들웨어를 바인딩해준 뒤
index.js
const express = require('express');
const posts = require('./routes/posts');
const users = require('./routes/users');
const app = express();
app.use(express.json());
app.use('/api/posts', posts);
app.use('/api/users', users);
app.listen(3000);
어플리케이션의 진입점이 될 index.js에서 각 모듈들의 API를 각각 다른 경로로 마운트했다.
이렇게 어플리케이션의 규모가 커지면 코드를 모듈별로 분할해 관리하기 때문에 router.use()
와 router.METHOD()
가 필요한 것이다.
router 인스턴스를 사용하지 않고 Application-level 미들웨어를 남발한다면 코드를 추적하기 매우 어려운 상황이 될 것이다.
4. Error-handling middlware
Error-handling 미들웨어는 다른 미들웨어와 동일하지만 3개가 아닌 4개의 argument가 있다.
function error(err, req, res, next) {
// log it
if (!test) console.error(err.stack);
// respond with 500 "Internal Server Error".
res.status(500);
res.send('Internal Server Error');
}
express가 이 미들웨어가 오류처리 미들웨어라는 것을 알려면 argument가 4개여야한다.
5. Built-in middleware
express에는 버전 4.x 부터 다음과 같은 내장 미들웨어가 있다.
express.static
html 파일, 이미지 등과 같은 정적 리소스를 제공한다.express.json
JSON 페이로드로 들어오는 요청을 구문 분석한다.express.urlencoded
URL로 인코딩된 페이로드로 들어오는 요청을 구문 분석한다.
6. Third-party middleware
기능 추가를 위해 third-party 미들웨어를 사용할 수 있다.
필요한 기능의 Node.js 모듈을 install 하고 해당 모듈을 application-level 또는 router-level로 바인딩하면된다.
$ npm install cookie-parser
const express = require('express');
const app = express();
const cookieParser = require('cookie-parser');
// load the cookie-parsing middleware
app.use(cookieParser());
참조
https://expressjs.com/en/guide/using-middleware.html#middleware.application