Express

Express

  • 경량 HTTP 웹 프레임워크

    • 요청과 응답
    • 미들웨어 사용
    • 템플릿 엔진 사용 가능
  • Express 미들웨어

    • 요청 분석 , 처리하는 모듈을 여러 개 쓸 수 있음
    • app.use(미들웨어)로 사용
    1
    2
    3
    4
    5
    app.use(function(req,res){
    res.send('Express');
    });

    // 이 경우 어떤 요청에 대한 함수인지 알 수 없음

  • npm install express로 시작

Express 생성 및 시작

1
2
3
4
5
6
7
8
9
10
11
12
13
var express = require('express');
var app = express();
// 객체 생성하는 것과 유사
// 여기까지가 세팅

app.use(function(req, res) {
res.send('Hello World');
// 미들웨어로 익명함수
// res.write와 비슷함
// http보다 편하게 사용 가능
});
app.listen(3000);
// 포트번호 3000번에서 대기

Http 모듈 서버와 Express 혼용

1
2
3
4
var http = require('http');
var express = require('express');
var app = express();
http.createServer(app).listen(3000);

Express 라우팅 (routing)

  • 요청에 따라 처리 미들웨어로 분배하는 것(프론트 컨트롤러의 역할)

  • HTTP Method 별로 라우팅 가능

    1
    2
    3
    4
    // GET 요청 - Hello Express로 응답
    app.get('/', function (req, res) {});
    // POST 요청 - 응답
    app.post('/', function (req, res) {});
  • URL 경로 별로 라우팅 가능(REST PULL 같은…)

    1
    2
    3
    4
    // user 경로에 GET 요청 - 응답
    app.get('/user', function (req, res) {});
    // items 경로에 GET 요청 - 응답
    app.get('/items', function (req, res) {});

Express 요청 분석

요청 분석

  • req.query : 쿼리 문자열
  • req.path : 요청 URL 중 경로
  • req.params : URL의 파라미터
  • req.cookie : 요청 메시지 내 쿠키(쿠키 파서 필요)
  • req.body : 요청 메시지 바디 분석(바디 파서 필요)

응답

  • res.json() : JSON 응답 메시지 전송
  • res.redirect() : 리다이렉션 응답 전송
  • res.render() : 템플릿으로 렌더링
  • res.send() : JSON, HTML, Buffer 전송, 메시지 헤더에 Content-Type 자동 설정
  • res.sendStatus() : 상태 코드와 상태 메시지 전송
  • res.status() : 상태 코드 설정. 응답 메소드 종료 안함
  • res.download() : 파일 다운로드

미들웨어

  • 함수 형태의 작은 모듈
  • 요청과 응답 처리 함수 형태

미들웨어 설정 하기

1
2
3
4
app.use(sayHello); 
function sayHello(req, res) {
res.send('Hello Express!!');
}

HTTP 메서드별 미들웨어 설정

1
2
3
4
app.get('/movies' , showMovieList);
app.post(‘/movies’, addMovieInfo);
app.put(‘/movies/:id’, updateMovieInfo);
// /:id라고 쓰면 id로 들어오는 것의 값을 뽑아 쓸 수 있다

next();

1
2
3
4
5
6
7
8
9
10
app.use(function(req, res, next) {
var now = new Date();
console.log(now.toDateString() + ' - url : ' + req.url);
// 다음 미들웨어 실행
next();
});

app.use(function(req, res) {
res.send('Hello Express!!');
});

하나의 요청에 다수의 미들웨어를 파라미터로 지정

1
2
3
4
5
6
7
8
//하나의 요청에 다수 미들웨어
// 두 미들웨어를 스택 형태로 설정
app.use(logger, sayHello);
// next()를 호출해야 sayHallo(req, res) 실행
function logger(req, res, next) {
next();
}
function sayHello(req, res) { }

그 외

  • 내장 미들웨어

  • 써드 파티 미들웨어

  • 정적 파일 요청 처리 미들웨어

    1
    2
    app.use(express.static(‘images’));
    // 정적 파일 경로 미리 만들어주고
    • 요청이 들어오면 자동으로 images 폴더 안에서 찾게끔

      SERVER-ADDRESS/cute1.jpg -> ./images/cute1.jpg

      SERVER-ADDRESS/images/cute1.jpg -> ./images/image/cute1.jpg

    • 가상 경로 설정

      1
      2
      3
      4
      5
      app.use('/static', express.static(‘files’));
      // 해당 url로 들어오면 files란 실제 폴더에서 찾는다

      // app.use(express.static(‘images’)); 와 다른 점은
      // url을 지정해준다는 점이 다름
    • 만약 실패하면 다음의 미들웨어 진행

      1
      2
      app.use(express.static('public')); 
      app.use(express.static('files'));

메서드 경로 별 라우팅 함수

1
2
3
4
5
6
7
8
9
10
11
12
app.get('/', function (req, res) {
res.send('GET request, /');
});
app.delete('/', function(req, res) {
res.send('DELETE method');
});
app.put('/item/1', function(req, res) {
res.send('PUT method, /item/1');
});
app.all('/all', function(req, res) {
res.send('모든 HTTP 메소드, /all');
});

메서드 별로도 라우팅이 가능하다.

위의 예제는 메서드 + 경로까지 합쳐서 라우팅 함수를 정의한 것

동적 파라미터의 문법

1
app.get(‘/user/:item’, [Callback]);

:블라블라가 핵심

사용할 때는 이렇게 쓴다.

다수의 동적 파라미터 사용이 가능하다.

사용 예제는 아래와 같다.

1
2
3
4
5
6
7
8
9
app.get('/user/:id', function (req, res) {
var userId = req.params.id;
...
});
app.get('/movies/:movieId/:actor', function (req, res) {
var movieId = req.params.movieId;
var actor = req.params.actor;
...
});

경로에 정규 표현식도 사용 가능

  • ? : 문자 존재하거나 생략

  • + : 1번 이상 반복

  • * : 임의의 문자

1
2
3
4
5
6
7
8
9
10
11
// /abcd, /acd
app.get('/ab?cd', function(req, res) {})

// /abcd, /abbcd, /abbbcd
app.get('/ab+cd', function(req, res) {})

// abcd, abxcd, abRABDOMcd, ab123cd
app.get('/ab*cd', function(req, res) {})

// /abe, /abcde
app.get('/ab(cd)?e', function(req, res) {})

에러 처리 미들웨어

에러 처리 방법
  • 미들웨어 내부에서 처리하거나
  • 에러 처리 미들웨어에게 위임
1
2
3
4
// 에러 파라미터는 아래와 같다.
app.use(function(err, req, res, next) {
res.status(500).send(‘에러 발생!');
});
1
2
3
4
5
6
// 에러 처리 미들웨어로 에러 전달
app.use(function(req, res, next) {
var error = new Error(‘에러 메세지’)
error.code = 100;
return next(error);
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 환경 별 에러 처리 코드
if (app.get('env') === 'development') {
// 환경 쪽에서 에러가 나면
app.use(function(err, req, res, next) {
res.end(err.stack);
});
// 미들웨어 실행
}
else {
app.use(function(err, req, res, next) {
res.status(err.code || 500);
res.end('잠시 후 다시 시도해주세요');
});
}

express의 route 함수

1
2
3
4
5
6
7
8
9
10
11
12
13
14
app.route(‘/book')
// 경로가 /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');
});

라우팅 로직 별로 분리 가능

1
2
3
4
5
6
7
// router.js

var express = require(‘expres’);
var router = express.Router();
router.get('/hello', sayHello);
router.get('/howAreYou/:who', sayThankYou);
module.exports = router;
1
2
3
// 이렇게 사용도 되고,

app.use(require('./router'));
1
2
3
//greeting/hello 경로의 요청이 들어오면 router 모듈 사용
// 이렇게 사용도 된다!
app.use('/greeting', require('./router’));

로그 처리

1
2
3
4
console.info(‘Info Message’);
console.log(‘Log Message’)
console.warn(‘Warn Message’)
console.error(‘Error Message’)

로그 미들웨어 (morgan)

  • npm install morgan로 시작

  • 요청과 응답을 자동으로 로그 남김

1
2
var morgan = require('morgan');
app.use(morgan('dev'));

바디 파서

  • POST 메서드 요청 : 요청 메시지 바디 분석 가능

  • npm install body-parser로 설치 필요

  • Body 메시지 인코딩 타입

    • json

      1
      2
      bodyParser.json(option)
      app.use(bodyParser.json());
    • Raw

    • Text

    • URL-Encoded

      1
      app.use(bodyParser.urlencoded({ extended: false }))
  • 바디파서는 멀티 파트 메세지 파싱 불가능
    (formidable , multer 같은 써드 파티 미들웨어 사용)

  • 사용 예제

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    // 바디파서를 사용하지 않은 기존 예제
    function addMovie(request, response) {
    var buffer = '';
    request.on('data', function(chunk) {
    buffer += chunk;
    });
    request.on('end', function() {
    // 바디 파싱
    var query = querystring.parse(buffer);
    var name = query.name;
    var director = query.director;
    });
    }

    위의 코드를 아래로

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    var express = require('express');
    var bodyParser = require('body-parser');
    var app = express();
    app.listen(3000);
    // 세팅해주고
    app.use(bodyParser.urlencoded({extended:false}));
    // extended 는 중첩된 객체표현을 허용할지 말지를 정하는 것
    // 객체 안에 객체를 파싱할 수 있게 하려면 true
    app.use(bodyParser.json());
    // 바디파서 세팅

    function addMovie(req, res) {
    var name = req.body.name;
    var director = req.body.director;
    }

    이렇게 쓴 예제도 있다

    1
    2
    3
    4
    5
    6
    7
    app.post('/', function (req, res) {
    var title = req.body.title;
    var message = req.body.message;

    res.send('title : ' + title + ' message : ' + message);

    });

    Express Template

    템플릿 엔진

    • ejs

      • HTML 태그 그대로 사용

        • 코드 실행 : <% %>

        • 결과 출력 : <%= %>

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        <% var value = ‘hello’ %>
        <%
        var i = 0
        var j = i + 1
        var data = [{title:'야구', image:’baseball.png’},…];
        %>
        <% if ( value ) { %>
        <div>
        <%= value %>
        <img src=“<%= data.image %>”>
        </div>
        <% } %>
        <% var tag = 'h1' %>
        <<%= tag %>> TAG 만들기 </<%= tag %>/>
    • jade

    1. Express 템플릿 설정

      1
      2
      3
      4
      5
      6
      app.set('views', [템플릿 폴더]);
      app.set('view engine', [템플릿 엔진]);

      // 예시
      app.set('views', __dirname + '/views');
      app.set('view engine', 'ejs');
    2. 템플릿에 적용 : 렌더링

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      res.render(view [, locals] [, callback])
      // locals : 템플릿의 지역 변수로 설정될 데이터
      // callback : 렌더링 콜백
      // 리졸버와 비슷함

      // 예시
      // index 템플릿 파일을 렌더링한 결과로 응답
      // 페이지만 준다
      res.render('index');
      // index 템플릿 파일에 name 이름으로 데이터를 제공
      res.render('index', { name: 'IU' } );
      // user 템플릿에 name 이름으로 데이터를 제공한다. 렌더링 한 결과를 다루는 콜백 함수 정의
      res.render('user', { name: 'IU' }, function(err, html) {
      // ...
      });
    3. 예시

      1
      2
      3
      4
      5
      6
      // js
      app.set('views', __dirname + '/views');
      app.set('view engine', 'ejs');
      var data = [{title:'야구', image:’baseball.png’},…];
      res.render('sports', {title:'구기 종목',sports:data});
      // sports는 배열이다
      1
      2
      3
      4
      5
      6
      7
      8
      9
      <!-- sports.ejs -->
      <h1><%= title %></h1>
      <ul>
      <% sports.forEach(function(item) { %>
      <!-- sports는 객체 배열,
      item에는 {title:'야구', image:’baseball.png’}가 들어온다 -->
      <li> <img src="images/<%= item.image %>" height="50px"> <%= item.title %> </li>
      <% }) %>
      </ul>