이전 글에서 express 개요와 간단한 웹서버 구축에 대해 알아보았다. 이번 글에서는 express의 핵심 개념인 미들웨어에 대해서 정리해보았다.
미들웨어란 무엇인가?
미들웨어 함수는 요청 오브젝트(req), 응답 오브젝트(res) 그리고 애플리케이션 요청-응답 주기 중 그 다음의 미들웨어 함수에 대한 액세스 권한을 갖는 함수입니다. 그 다음의 미들웨어 함수는 일반적으로 next 라는 이름의 변수로 표시됩니다.
공식 문서에서는 미들웨어를 위와 같이 설명하고 있다. 클라이언트에서 요청이 왔을 때 응답을 보내기 위한 과정 중간에서 목적에 맞게 무언가 처리를 하는 함수를 미들웨어 함수라고 한다.
express 프레임워크는 기본적으로 라우팅 처리를 위해 여러가지 미들웨어를 호출하고 사용하며, 이는 요청이 들어온 이후부터 응답이 되기 전까지 이어진다. 미들웨어 함수는 request 객체와 response 객체 그리고 next를 인자로 받아 사용할 수 있으며, 함수 내에서 목적에 맞는 처리를 한 뒤 next로 다음 미들웨어를 호출하여 사용할 수 있다. 따라서 Express-based 애플리케이션은 이런 미들웨어 함수 호출들로 구성되어 있다고 볼 수 있다.
request body 파싱하기
요청이 들어왔을 때 request 객체에 접근해 그 body를 파싱하는 것도 미들웨어를 통해 처리할 수 있다. http 모듈에서 request 객체에 이벤트를 달아 처리했던 것에 비해 비교적 간단하다.
위 그림에서 1번에 해당하는 과정인데, 이전에는 body-parser 라는 모듈을 이용했지만, Express v4.16.9 부터는 express.json 이라는 빌트인 미들웨어가 생겨서 과정이 더 간소화되었다. 별도의 설치 없이 아래의 코드를 작성하면, request body에 대해 파싱된 결과물로 접근할 수 있게 된다.
const jsonParser = express.json();
# 특정 요청에 대해 적용할 수 있다.
app.post('/api/users', jsonParser, function (req, res) {...})
# 모든 요청에 대해 적용할 수 있다.
app.use(express.json());
CORS 설정하기
미들웨어를 사용하면 요청에 대한 CORS 설정도 http 모듈에 비해 훨씬 간편하게 처리해줄 수 있다. http 모듈에서는 프리플라이트 요청 즉, 요청 method가 OPTIONS 인지 확인한 뒤에 헤더에 'Access-Control-Allow-Origin' 을 추가해 응답하는 과정을 직접 해주어야 했는데, express 에서는 cors() 라는 미들웨어를 제공하기 때문에, 아래와 같이 코드를 작성하면 된다.
const cors = require('cors');
app.use(cors());
미들웨어 직접 작성하기!
앞서 설명한 것 처럼 미들웨어란 요청과 응답 사이에서 정해진 역할을 하기 위해 사용되는 함수를 의미한다.
위 그림과 같이 미들웨어 함수는 req 객체, res 객체 그리고 next 를 인자로 받고 있다. 미들웨어 함수는 정해진 역할을 한 뒤에 다음 할 일(미들웨어)를 호출해서 연결해주는 중간다리 같은 역할이기 때문에, 미들웨어 안에서 요청에 응답하지 않는다면 반드시 next를 이용해 다음 미들웨어를 호출해주어야 한다. 그렇지 않으면 서버가 응답을 하지 않고 다음 단계로도 넘어가지 않는 상태가 되어버린다.
# 별도의 라우터를 import하여 /test 경로로 사용한다.
const testRouter = require('./router/testRouter');
app.use('/test', testRouter);
# 현재 시간을 찍어주는 미들웨어 함수
const logger = function (req, res, next) {
console.log(new Date().toLocaleString());
next();
};
# 전체 요청에 대해 logger 함수를 실행한다.
app.use(logger);
# 루트 경로로 서버 연결을 체크한다.
app.get('/', (req, res, next) => {
res.status(200).send('서버 연결되었습니다.');
});
위 예시에서는 logger 함수를 정의한 뒤에 app.use 를 이용해 전체 요청에 대해 logger 함수가 실행되도록 하고있다. postman으로 요청을 보내 정상 동작하는지 확인해보자.
참고로 이 미들웨어가 사용된다고 선언된 위치가 중요한데, /test 경로로 들어오는 요청에 대해서는 이 미들웨어가 실행되지 않는다. 왜냐하면 미들웨어를 사용하겠다고 선언한 시점 이전에 코드가 위치하기 때문이다.
app.use 는 무슨 의미인가?
먼저 app은 `const app = express()` 로 정의된 서버를 시작할 수 있는 객체이다. 이 객체에서 여러 express 메서드를 사용할 수 있는데, use는 그 메서드 중 하나이다. 이 함수를 사용하면 특정 경로에 특정 미들웨어 함수를 마운트할 수 있다. 특정 경로와 미들웨어가 주어질 때 해당 미들웨어는 특정 경로에 일치하는 요청이 왔을 때만 실행된다.
app.use([path,] callback [, callback...])
use 에 path를 전달하는 것은 옵션인데, 전달되지 않을 경우 root path( / ) 가 사용된다. path 전달이 생략된 경우에는 앞서 본 것 처럼 '모든' 요청에 대해서 전달된 callback - 미들웨어 함수가 실행된다.
app.use('/test', testRouter);
위 코드의 의미는 /test 경로에 대한 요청에 testRouter 를 실행하겠다는 의미이다. 이 testRouter 는 express.Router 를 사용해 작성된 라우터 모듈이다.
라우팅 관리는 미들웨어와 함께 express의 또 다른 장점 중 하나이다. 다음 글에서 더 자세히 알아보자!
참고자료
https://www.geeksforgeeks.org/middleware-in-express-js/
https://morian-kim.tistory.com/3
'Stacks > Node.js' 카테고리의 다른 글
[Node.js / express] express.js 기본 내용 정리 (0) | 2022.08.17 |
---|