MERN stack은 JavaScript 생태계에서 인기 있는 프레임워크인 MongoDB, Express, React, Node.js를 지칭하는 말이다.
이 중에서 Express는 (1) Node.js 환경에서 (2) 웹 서버, 또는 API 서버를 제작하기 위해 사용되는 인기 있는 프레임워크이다.
Express로 구현한 서버가 Node.js HTTP 모듈로 작성한 서버와 다른 점은 다음과 같다.
이번 포스팅에서는 Express 공식 문서를 따라 간단한 웹 서버를 만들어 보겠다.
Express로 간단한 웹 서버 만들어보기
1. Express 설치
나의 경우, Express 공식 문서의 시작하기 - 설치 를 참고해서 아예 연습폴더를 만든 후, 설치해보았다.
공식 문서 설명이 잘 되어있어 웬만하면 읽어보는 것을 추천한다.
npm install express
2. 간단한 웹 서버 만들기
Express 공식 문서의 시작하기 - Hello world 예제 를 참고하여 아래 코드를 그대로 app.js파일에 추가했다.
const express = require('express')
const app = express()
const port = 3000
app.get('/', (req, res) => {
res.send('Hello World!') // 🟣 (설명1)
})
app.listen(port, () => {
console.log(`Example app listening on port ${port}`)
})
결과는 아래와 같다.
- 앱은 서버를 시작하며 3000번 포트에서 연결을 청취한다.
- 앱은 루트 URL(/) 또는 라우트에 대한 요청에 "Hello World!"로 응답한다.
- 다른 모든 경로에 대해서는 404 Not Found로 응답한다.
🟣 (설명 1) 응답 메소드
다음 표에 표시된 응답 오브젝트에 대한 메소드(res)는 응답을 클라이언트로 전송하고 요청-응답 주기를 종료할 수 있다.
라우트 핸들러로부터 다음 메소드 중 어느 하나도 호출되지 않는 경우, 클라이언트 요청은 정지된 채로 방치된다.
res.download() | 파일이 다운로드되도록 프롬프트 |
res.end() | 응답 프로세스를 종료 |
res.json() | JSON 응답을 전송 |
res.jsonp() | JSONP 지원을 통해 JSON 응답을 전송 |
res.redirect() | 요청의 경로를 재지정 |
res.render() | 보기 템플리트를 렌더링 |
res.send() | 다양한 유형의 응답을 전송 |
res.sendFile() | 파일을 옥텟 스트림의 형태로 전송 |
res.sendStatus() | 응답 상태 코드를 설정한 후 해당 코드를 문자열로 표현한 내용을 응답 본문으로서 전송 |
- 예) res.sendFile() 을 이용해서 html 파일을 보낼 수도 있다.
3-1. 라우팅: 메서드와 url에 따라 분기(Routing)하기
- Express 공식 문서의 시작하기 - 기본 라우팅을 참고하는 것을 추천한다.
- 특정 메서드와 url(/lower, /upper 등)로 분기점을 만드는 것을 라우팅(Routing)이라고 한다.
- 클라이언트는 특정한 HTTP 요청 메서드(GET, POST 등)와 함께 서버의 특정 URI(또는 경로)로 HTTP 요청을 보낸다.
- 라우팅은 클라이언트의 요청에 해당하는 Endpoint에 따라 서버가 응답하는 방법을 결정하는 것이다.
app.METHOD(PATH, HANDLER)
// app은 express의 인스턴스
// 여기서 METHOD는 HTTP 요청 메소드
// PATH는 서버에서의 경로
// HANDLER는 라우트가 일치할 때 실행되는 함수
// ** 홈 페이지에서 Hello World!로 응답:
app.get('/', function (req, res) {
res.send('Hello World!');
});
// ** 애플리케이션의 홈 페이지인 루트 라우트(/)에서 POST 요청에 응답:
app.post('/', function (req, res) {
res.send('Got a POST request');
});
// ** user 라우트에 대한 PUT 요청에 응답:
app.put('/user', function (req, res) {
res.send('Got a PUT request at /user');
});
// ** user 라우트에 대한 DELETE 요청에 응답:
app.delete('/user', function (req, res) {
res.send('Got a DELETE request at /user');
});
- 미들웨어와 비슷하게 작동하는 여러 콜백 함수를 제공하여 요청을 처리할 수 있다.
- 유일한 차이점은 이러한 콜백은 next('route')를 호출하여 나머지 라우트 콜백을 우회할 수도 있다는 점이다.
- 이러한 메커니즘을 이용하면 라우트에 대한 사전 조건을 지정한 후, 현재의 라우트를 계속할 이유가 없는 경우에는 제어를 후속 라우트에 전달할 수 있다.
- 2개 이상의 콜백 함수는 하나의 라우트를 처리할 수 있다. 단, next 오브젝트를 반드시 지정해야 한다. (아래 참고)
app.get('/example/b', function (req, res, next) {
console.log('the response will be sent by the next function ...');
next();
}, function (req, res) {
res.send('Hello from B!');
});
- 하나의 콜백 함수 배열은 하나의 라우트를 처리할 수 있다. (아래 참고)
var cb0 = function (req, res, next) {
console.log('CB0');
next();
}
var cb1 = function (req, res, next) {
console.log('CB1');
next();
}
var cb2 = function (req, res) {
res.send('Hello from C!');
}
app.get('/example/c', [cb0, cb1, cb2]);
3-2. express.Router
express 사용하지 않은 코드와 비교해보기
추가적인 라이브러리를 사용하지 않고, 순수한 Node.js로 코드를 작성하면, 다음과 같이 작성할 수 있다.
Node.js로 라우팅을 구현한 코드 (if문 사용)
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
})
- express.Router 클래스를 사용하면 모듈식 마운팅 가능한 핸들러를 작성할 수 있다.
- Router 인스턴스는 완전한 미들웨어이자 라우팅 시스템이며, 따라서 “미니 앱(mini-app)”이라고 불리는 경우가 많다.
- 다음 예에서는 라우터를 모듈로서 작성하고, 라우터 모듈에서 미들웨어 함수를 로드하고, 몇몇 라우트를 정의하고, 기본 앱의 한 경로에 라우터 모듈을 마운트한다.
다음의 내용이 입력된 birds.js라는 이름의 라우터 파일을 앱 디렉토리에 작성
var express = require('express');
var router = express.Router();
// middleware that is specific to this router
router.use(function timeLog(req, res, next) {
console.log('Time: ', Date.now());
next();
});
// define the home page route
router.get('/', function(req, res) {
res.send('Birds home page');
});
// define the about route
router.get('/about', function(req, res) {
res.send('About birds');
});
module.exports = router;
이후 앱 내에서 다음과 같이 라우터 모듈을 로드한다.
앱은 이제 /birds 및 /birds/about에 대한 요청을 처리할 수 있게 되었으며,
해당 라우트에 대한 특정한 미들웨어 함수인 timeLog를 호출할 것이다.
var birds = require('./birds');
...
app.use('/birds', birds);
3-3. app.route()
- app.route()를 이용하면 라우트 경로에 대하여 체인 가능한 라우트 핸들러를 작성할 수 있다.
- 경로는 한 곳에 지정되어 있으므로, 모듈식 라우트를 작성하면 중복성과 오타가 감소하여 도움이 된다. (Router() 문서를 참조)
- app.route()를 사용하여 정의된 체인 라우트 핸들러의 예는 다음과 같다.
app.route('/book')
.get(function(req, res) {
res.send('Get a random book');
})
.post(function(req, res) {
res.send('Add a book');
})
.put(function(req, res) {
res.send('Update the book');
});
728x90
'FE > Server' 카테고리의 다른 글
쿠키(Cookie)의 개념과 작동원리 (0) | 2023.05.02 |
---|---|
mkcert를 이용한 로컬에서 HTTPS 서버 만들기 (0) | 2023.04.28 |
[Network] Airline 서버 구현 (2) : 서버 개발하기 (0) | 2023.04.09 |
[Network] Airline 서버 구현 (1) : Airline Server API document (0) | 2023.04.06 |
[Network] HTTP 모듈을 사용한 서버 다뤄보기 (0) | 2023.04.04 |