Express.js 소개
MERN stack은 JavaScript 생태계에서 인기 있는 프레임워크인 MongoDB, Express, React, Node를 지칭하는 말입니다.
이 중에서 Express.js는 Node.js 환경에서 웹 서버, 또는 API 서버를 제작하기 위해 사용되는 인기 있는 프레임워크입니다.
Express로 구현한 서버가 http 모듈로 작성한 서버와 다른 점은 다음과 같습니다.
- 미들웨어 추가가 편리하다.
- 자체 라우터를 제공한다.
공식 문서를 따라 Express로 간단한 웹 서버를 만들 수 있습니다.
순수한 node.js 코드로 라우팅을 구현한 아래의 코드
const requestHandler = (req, res) => {
if(req.url === '/lower') {
if (req.method === 'GET') {
res.end(data)
} else if (req.method === 'POST') {
req.on('data', (req, res) => {
// do something ...
})
}
}
}
Express는 프레임워크 자체에서 라우터 기능을 제공합니다.
Express의 라우터를 활용하면 아래와 같이 직관적인 코드를 작성할 수 있습니다.
const router = express.Router()
router.get('/lower', (req, res) =>{
res.send(data)
})
router.post('/lower', (req, res) =>{
// do something
})
Middleware
미들웨어는 자동차 공장의 공정과 비슷합니다. 컨베이어 벨트 위에 올라가 있는 request에 필요한 기능을 더하거나, 문제가 발견된 불량품을 밖으로 걷어내는 역할을 합니다. 미들웨어는 express의 가장 큰 장점입니다.
자주 사용하는 미들웨어
미들웨어는 말 그대로 프로세스 중간에 관여하여 특정 역할을 수행합니다. 먼저, 미들웨어를 사용하는 상황은 다음과 같습니다.
1. 모든 요청에 대해 url이나 메소드를 확인할 때
endpoint가 /이면서, 클라이언트로부터 GET 요청을 받았을 때 적용되는 미들웨어입니다. 파라미터의 순서에 유의해야 합니다. req, res는 우리가 잘 아는 요청(request)/응답(response)이고, next는 다음 미들웨어를 실행합니다. 이 콘텐츠의 최상단에 나오는 이미지에서 next 의 역할을 확인할 수 있습니다. 위 그림을 살펴보면, 미들웨어 내부에서는 아무런 작업을 하고 있지 않습니다. 그저 next() 함수를 호출하여 다음 미들웨어로 데이터를 전달하고 있습니다.
만약 특정 enpoint가 아니라 모든 요청에 동일한 미들웨어를 적용하려면 메소드 app.use 를 사용합니다.
모든 요청에 대해 LOGGED가 출력되는 걸 확인할 수 있습니다.
const express = require('express');
const app = express();
const myLogger = function (req, res, next) {
console.log('LOGGED'); // 이 부분을 req, res 객체를 이용해 고치면, 여러분들은 모든 요청에 대한 로그를 찍을 수 있습니다.
next();
};
app.use(myLogger);
app.get('/', function (req, res) {
res.send('Hello World!');
});
app.listen(3000);
2. POST 요청 등에 포함된 body(payload)를 구조화할 때(쉽게 얻어내고자 할 때)
순수 node.js로 HTTP body(payload)를 받을 때에는 Buffer를 조합해서 다소 복잡한 방식으로 body를 얻을 수 있습니다.
let body = [];
request.on('data', (chunk) => {
body.push(chunk);
}).on('end', () => {
body = Buffer.concat(body).toString();
// body 변수에는 문자열 형태로 payload가 담겨져 있습니다.
});
body-parser 미들웨어를 사용하면 위 과정을 아래처럼 간단하게 처리할 수 있습니다.
const bodyParser = require('body-parser')
const jsonParser = bodyParser.json()
// 생략
app.post('/api/users', jsonParser, function (req, res) {
// req.body에는 JSON의 형태로 payload가 담겨져 있습니다.
})
3. 모든 요청/응답에 CORS 헤더를 붙여야 할 때
순수 node.js 코드에 CORS 헤더를 붙이려면, 응답 객체의 writeHead 메소드 등을 이용합니다. 이런 메소드를 이용하더라도 Access-Control-Allow-* 헤더를 매번 재정의해야 합니다. 그뿐만 아니라, OPTIONS 메소드에 대한 라우팅도 따로 구현해야 합니다.
const defaultCorsHeader = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Accept',
'Access-Control-Max-Age': 10
};
// 생략
if (req.method === 'OPTIONS') {
res.writeHead(201, defaultCorsHeader);
res.end()
}
cors 미들웨어를 사용하면 위 과정을 아래 코드처럼 간단하게 처리할 수 있습니다.
const cors = require('cors')
// 생략
app.use(cors()) // 모든 요청에 대해 CORS 허용
특정 요청에만 cors 모듈을 적용할 수도 있습니다.
const cors = require('cors')
// 생략
// 특정 요청에 대해 CORS 허용
app.get('/products/:id', cors(), function (req, res, next) {
res.json({msg: 'This is CORS-enabled for a Single Route'})
})
4. 요청 헤더에 사용자 인증 정보가 담겨있는지 확인할 때
다음은 HTTP 요청에서 토큰이 있는지 여부를 판단하여, 이미 로그인한 사용자일 경우 성공, 아닐 경우 에러를 보내는 미들웨어 예제입니다.
app.use((req, res, next) => {
// 토큰 있니? 없으면 받아줄 수 없어!
if(req.headers.token){
req.isLoggedIn = true;
next()
} else {
res.status(400).send('invalid user')
}
})
'Computer Science > Server, 네트워크' 카테고리의 다른 글
[네트워크] HTTP 헤더 (0) | 2021.08.09 |
---|---|
[네트워크] 인터넷 프로토콜 (IP, TCP/UDP, HTTP) (0) | 2021.08.09 |
[Server] OAuth 2.0 (0) | 2021.08.04 |
[Server] 보안 인증 (Token-JWT) (0) | 2021.08.03 |
[Server] 보안 인증 기초 (HTTPS/Hashing/cookie/CSRF) (0) | 2021.08.02 |