본문 바로가기

[Network] Express로 간단한 웹 서버 만들어보기 (라우터)

[Network] Express로 간단한 웹 서버 만들어보기 (라우터)

MERN stack은 JavaScript 생태계에서 인기 있는 프레임워크인 MongoDB, Express, React, Node.js를 지칭하는 말이다.

이 중에서 Express는 (1) Node.js 환경에서 (2) 웹 서버, 또는 API 서버를 제작하기 위해 사용되는 인기 있는 프레임워크이다.

 

Express로 구현한 서버가 Node.js HTTP 모듈로 작성한 서버와 다른 점은 다음과 같다.

 

  1. 라우터를 제공한다. (해당 포스팅)
  2. 미들웨어를 추가할 수 있다. (다음 포스팅)

이번 포스팅에서는 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
⬆︎