본문 바로가기

TIL ( CODESTATES)

Express - 라우팅, 미들웨어의 작성 및 사용

공부하는 이유

chatterbox server를 express를 이용해서 refactoring하는 것이 이번 과제이다. 

미들웨어가 무엇인지 알고 그 중 body parser, cors 라는 미들웨어를 적용해 보는 것이 그 내용이다. 

 

여기서는 과제를 다루기 전 기본적으로 routing에 대해서 이해하고, 미들웨어를 어떻게 작성하는지, 사용하는지 공부한 것을 기록한다.

모든 내용은 express 공식문서의 내용을 바탕으로 한다.

 

 

 


라우팅

라우팅은 URI(또는 경로) 및 특정한 HTTP 요청 메소드(GET, POST 등)인 특정 end point에 대한 클라이언트 요청에 애플리케이션이 응답하는 방법을 결정하는 것을 말한다.

 

각 라우트는 하나 이상의 handler 함수를 가질 수 있는데, 이러한 함수는 라우터가 일치할 때 실행된다.

app.METHOD(PATH, HANDLER)

METHOD는 미들웨어 함수가 처리하는 요청(GET, PUT,POST 등)의 소문자로 된 HTTP 메소드이다.

 

 

사용 예:

 

애플리케이션의 홈 페이지인 루트 라우트(/)에서 GET 요청에 응답

var express = require('express');
var app = express(); // app은 express의 인스턴스!

app.get('/', function(req, res) { // 루트라우트(애플리케이션의 홈 페이지)에서 GET 요청이 들어오면
  res.send('hello world'); // 'hello world'로 응답한다.
});

 

 

 


Express 앱에서 사용할 미들웨어 작성하기

 

먼저, 미들웨어 함수는

  • 요청 오브젝트(req),
  • 응답 오브젝트(res),
  • 그 다음 미들웨어 함수(next)

에 대한 액세스 권한을 갖는 함수이다.

 

 

 

미들웨어 함수는

  • 모든 코드를 실행하거나,
  • 요청 및 응답 오브젝트에 대한 변경을 실행하거나,
  • 요청-응답 주기를 종료하거나,
  • 스택 내의 그 다음 미들웨어를 호출할 수 있다.

 

* 현재 미들웨어 함수가 요청-응답 주기를 종료하지 않는 경우에는 next()를 호출해서 그 다음 미들웨어 함수에 제어를 전달해야 한다.

그렇지 않으면 해당 요청은 정지된 채 방치된다.

 

 

사용 예 1 :

앱이 실행될 때마다 단순히 콘솔에 LOGGED를 출력한다.

var express = require('express');
var app = express();

var myLogger = function(req, res, next) { // myLogger 라는 미들웨어 함수는 
  consolelog('LOGGED'); // 단순히 콘솔에 LOGGED를 인쇄한다.
  next(); // 그 다음 미들웨어를 호출한다.
}

app.use(myLogger); // 미들웨어 함수를 로드하기 위해 app.use()를 호출한다.

app.get('/', function(req, res) {
  res.send('Hello World');
});

app.listen(3000);

위 코드는 루트 경로(/)로 라우팅하기 전에 myLogger 미들웨어 함수를 로드한다.

 

next()함수는 Node.js 또는 Express API의 일부가 아니지만, 미들웨어 함수에 전달되는 세 번째 인수이다.

next() 함수에 다른 이름을 지정할 수도 있지만 일반적으로 next라고 하므로 혼란을 방지하기 위해 이 방식을 사용하는 것이 낫다.

 

 

사용 예 2 :

앱의 루트에 대한 req를 실행할 때 앱은 req의 타임스탬프를 브라우저에 표시한다.

var express = require('express');
var app = express();

var requestTime = function(req, res, next){
  req.resquestTime = Date.now(); // requestTime이라는 특성을 req에 추가한다.
  next();
};

app.use(requestTime);

app.get('/', function(req, res){ // 콜백 함수는 미들웨어 함수가 req에 추가하는 특성을 사용한다.
  var responseText = 'Hello world!';
  responseText += 'Requested at: ' + req.requestTime + '';
  res.send(responseText);
});

app.listen(3000);
  

 

 

 


미들웨어 사용하기

Express는 자체적인 최소한의 기능을 갖춘 라우팅 및 미들웨어 웹 프레임워크이며,

Express 애플리케이션은 기본적으로 일련의 미들웨어 함수 호출이다.

 

 

미들웨어가 주로 쓰이는 상황

  • 모든 요청에 대해 url이나 메소드를 알고자 할 때
  • POST 요청 등에서 쓰이는 body(payload)를 쉽게 얻어내고자 할 때
  • 모든 요청/응답에 CORS 헤더를 붙일 때
  • 요청 헤더에 사용자 인증 정보가 담겨있는지 확인하고자 할 때

 

Express 애플리케이션은 다음과 같은 유형의 미들웨어를 사용할 수 있다.

  • 애플리케이션 레벨 미들웨어
  • 라우터 레벨 미들웨어
  • 오류 처리 미들웨어
  • 기본 제공 미들웨어
  • Third-party 미들웨어

 

 

 

 - 애플리케이션 레벨 미들웨어

app.use() 및 app.METHOD() 함수를 이용해 애플리케이션 미들웨어를 웹 오브젝트(Express)의 인스턴스에 바인드한다.

애플리케이션 레벨 및 라우터 레벨 미들웨어는 선택적인 마운트 경로를 통해 로드할 수 있다. 

 

사용 예 1 :

마운트 경로가 없는 미들웨어 함수이다. 이 함수는 앱이 요청을 수신할 때마다 실행된다.

var app = express();
app.use(function(req, res, next) { // 경로가 지정되어 있지 않다.
  console.log('Time: ', Date.now());
  next();
});

 

사용 예 2 :

/user/:id 경로에서 GET 요청이 왔을 때 응답을 주는 미들웨어 함수이다.

app.get('/user/:id', function(req, res, next){
  res.send('USER');
});

 

사용 예 3 :

/user/:id 경로에 마운트되는 미들웨어 함수이다. 이 함수는 /user/:id 경로에 대한 모든 유형의 HTTP 요청에 대해 실행된다.

하나의 경로에 여러 미들웨어 함수를 정의할 수 있다.

app.use('/user/:id', function(req, res, next) {
  console.log('Request URL: ', req.originalUrl);
  next();
}, function(req, res, next) {
  console.log('Request Type: ', req.method);
  next();
});

 

사용 예 4 :

하나의 경로에 여러 라우트를 정의할 수도 있다.

app.get('/user/:id', function (req, res, next) { // 첫번째 라우터
  console.log('ID:', req.params.id);
  next();
}, function (req, res, next) {
  res.send('User Info'); // next()를 호출하지 않기 때문에 두번째 라우터는 호출되지 않는다.
});

// handler for the /user/:id path, which prints the user ID
app.get('/user/:id', function (req, res, next) { // 두번째 라우터
  res.end(req.params.id);
});

 

사용 예 5:

라우터 미들웨어 스택의 나머지 미들웨어 함수들을 건너뛰려면 next('route') 를 호출하여 다음 라우트로 제어를 전달할 수 있다.

app.get('/user/:id', function (req, res, next) { // 첫번째 라우트 , 첫번째 미들웨어함수
  if (req.params.id == 0) next('route'); // 참이면 다음 라우트에 제어를 전달한다.
  else next(); //그렇지 않으면 이 스택에서 다음 미들웨어 함수에 제어를 전달한다.
}, function (req, res, next) { // 두번째 미들웨어 함수
  // render a regular page
  res.render('regular');
});

// handler for the /user/:id path, which renders a special page
app.get('/user/:id', function (req, res, next) { // 두번째 라우트
  res.render('special');
});

 

 

 - 라우터 레벨 미들웨어

expres.Router() 인스턴스에 바인드된다는 점을 제외하면 애플리케이션 레벨 미들웨어와 동일한 방식으로 동작한다.

router.use() 및 router.METHOD() 함수를 사용하여 라우터 레벨 미들웨어를 로드할 수 있다.

 

 

 

 

- 오류 처리 미들웨어

오류 처리 미들웨어는 항상 (err, req, res, next) 4개의 인수를 필요로 한다. next 오브젝트를 사용할 필요는 없지만 시그니처를 유지하기 위해 지정해야 한다.

app.use(function(err, req, res, next) {
  console.error(err.stack);
  res.status(500).send('Something broke!');
});

 

 

 

 

- 기본 제공 미들웨어 Express.static(root, [options])

Express의 유일한 기본 제공 미들웨어 함수는 express.static 이다. 이 함수는 Express 애플리케이션의 정적 자산을 제공하는 역할을 한다. 

root 인수는 정적 자산의 제공을 시작하는 위치가 되는 루트 디렉토리를 지정한다.

하나의 앱은 2개 이상의 정적 디렉토리를 가질 수 있다.

 

 

 

 

-Third-Party 미들웨어

필요한 기능을 위한 Node.js 모듈을 설치한 후, 애플리케이션 레벨 또는 라우터 레벨에서 해당 모듈을 앱에 로드하면 된다.

 

사용 예 :

body parser : Node.js 본문을 파싱하는 미들웨어이다.

req.body의 핸들러에 전달하기 전 미들웨어에서 들어오는 요청 본문의 구문을 분석한다.

//설치
npm install body-parser 

//API
var bodyParser = require('body-parser')

 

body parser는 다음과 같은 모듈을 제공한다.

  • JSON body parser
  • Raw body parser
  • Text body parser
  • URL-encoded from body parser

 

여기서는 JSON body parser를 살펴보려고 한다.

 

bodyParser.json()

Content-Type 헤더가 type 옵션과 일치하는 요청이 있을 때 json 요청만 파싱하는 미들웨어를 반환한다.

 

var bodyParser = require('body-parser')
var jsonParser = bodyParser.json()

app.post('/api/users', jsonParser, function(req, res) { // jsonParser를 붙여주었기 때문에
  // req.body에는 JSON의 형태로 payload가 담겨져 있다.