본문 바로가기

Back-End/Node.js

Express - 9.1. 미들웨어의 사용 - body parser

반응형

Express의 중요한 기능 두 가지

1. Route

2. Middleware

 

이전에도 말했듯이, Express에서는 처음부터 코드를 작성하지 않고 다른 이가 작성한 소프트웨어를 부품으로 하여 나의 소프트웨어를 만들어간다. 이를 미들웨어라고 한다.

 

미들웨어 사용

Express 공식 페이지> 미들웨어 사용 을 클릭해보자.

 

Express 미들웨어 사용

미들웨어 사용 Express는 자체적인 최소한의 기능을 갖춘 라우팅 및 미들웨어 웹 프레임워크이며, Express 애플리케이션은 기본적으로 일련의 미들웨어 함수 호출입니다. 미들웨어 함수는 요청 오��

expressjs.com

Third-party middleware

: 다른 이들이 만든 미들웨어. 즉, express가 만들지 않은, 비공식적인 미들웨어 

여러 가지 유명한 써드파티 미들웨어 리스트

 

Express 미들웨어

Express 미들웨어 목록에 적힌 Express 미들웨어 모듈들은 Expressjs 팀이 유지보수합니다. 미들웨어 모듈 설명 내장 함수 (Express 3) body-parser HTTP 요청 body를 파싱합니다. body, co-body, 그리고 raw-body도 참��

expressjs.com

body-parser

많은 미들웨어 중에서 body-parser를 사용해보자. 

- body: 웹 브라우저에서 요청한 정보의 본체. 이 본체를 설명하는 데이터를 header라 한다.

즉, 이 본체 데이터를 분석(parser)하여 우리가 필요한 형태의 데이터로 가공해주는 것 body-parser이다.

//4. create>제출 버튼 클릭 시 페이지
app.post('/create', function(request, response){
  var body = '';
  request.on('data', function(data){
    body = body + data;
  });
  request.on('end', function(){
    var post = qs.parse(body);
    var title = post.title;
    var description = post.description;
    fs.writeFile(`data/${title}`, description, 'utf8',
    function(err) {
      response.redirect(`/page/${title}`);
    });
  });
});

현재 post>create는 글을 생성했을 때, 생성된 데이터를 받아서 데이터를 처리하는 코드이다. 이때 데이터는 post방식으로 처리되기 때문에 get방식과는 다르게 post방식은 데이터의 크기가 클 수 있다. 그래서 var body 변수를 정의하고, 데이터가 추가 될 때마다 request.on('data', 의 function이 호출이 되는데  그 때마다 기존 body 변수에 도착한 data를 추가시켜준다. 그리고 request.on('end'  즉 더이상 데이터가 없다는 이벤트가 발생했을 때, 실체 처리를 해주는 코드이다.

위처럼 코드를 작성해도 되지만, 미들웨어인 body-parser로 작성하게 되면 코드를 더 우아하게 짤 수 있으며, 발생할 문제를 해결해준다.

Middleware installation

npm install body-parser

 

Express body-parser middleware

body-parser Node.js body parsing middleware. Parse incoming request bodies in a middleware before your handlers, available under the req.body property. Note As req.body’s shape is based on user-controlled input, all properties and values in this object a

expressjs.com

 

API

body-parser 설치 후, 다음으로 불러온다.

const bodyParser = require('body-parser');

사용자가 json데이터로 요청을 한다면 아래 코드를 작성하고,

app.use(bodyParser.json());

form데이터의 경우 아래 코드를 작성한다.

app.use(bodyParser.urlencoded({ extended: false }));

app.use에 bodyParser를 호출하게 되면, 속의 코드가 실행되면서 그 결과로 미들웨어가 들어오게 된다. 즉, body-parser가 만들어내는 미들웨어를 표현하는 표현식이다.

이렇게 작성하게 되면, main.js가 실행될 때마다, 즉 사용자가 요청할 때마다 위 코드에 의해 만들어진 미들웨어가 실행된다. 이 미들웨어가 어떻게 생겼는지는 알 필요가 없다. 내부적으로는 사용자가 전송한 post데이터를 분석하여 모든 데이터를 가져온 다음 /create경로에 해당하는 콜백함수를 호출하도록 약속되어 있다. 그리고 호출하면서 첫 번째 인자인 request 파라미터 변수에 (원래는 body라는 property가 없었지만) body-parser 미들웨어가 request에 body property를 만들어준다.

그리고 이를 통해 코드를 아래와 같이 변경할 수 있게 된다.

//4. create>제출 버튼 클릭 시 페이지
app.post('/create', function(request, response){
  var post = request.body;
  var title = post.title;
  var description = post.description;
  fs.writeFile(`data/${title}`, description, 'utf8',
  function(err) {
    response.redirect(`/page/${title}`);
  });
});

 결론

이전 코드는 난잡했는데, body-parser 미들웨어를 아래 코드를 통해 장착하고 나니

app.use(bodyParser.urlencoded({ extended: false }));

내부적으로 body-parser가 동작하여, create 라우트를 사용할 때 request 객체의 body property에 접근하는 것을 통해 간결한 코드를 작성할 수 있게 된다.

 

이와 동일하게 post>update와 delete 코드도 변경할 수 있다.

post>update

//6. update>제출 버튼 클릭 시 페이지
app.post('/update', function(request, response){
  var post=  request.body;
  var id = post.id;
  var title = post.title;
  var description = post.description;
  fs.rename(`data/${id}`, `data/${title}`, function(err){
    fs.writeFile(`data/${title}`, description, 'utf8',
    function(err) {
      response.redirect(`/page/${title}`);
    });
  });
})

delete

//7. delete 버튼 클릭 시 페이지
app.post('/delete_process', function(request, response){
 var post = request.body;
  var id = post.id;
  var filteredId = path.parse(id).base;
  fs.unlink(`data/${filteredId}`, function(error){
    response.redirect('/');
  });
})

 

 

전체 코드

const express = require('express');
const app = express();
const fs = require('fs');
const path = require('path');
const qs = require('querystring');
const sanitizeHtml = require('sanitize-html');
const template = require('./lib/template');
const bodyParser = require('body-parser');
const port = 3000;

app.use(bodyParser.urlencoded({ extended: false }));

// 1. 홈 페이지
// app.get('/', (req, res) => {  res.send('Hello World!')})
app.get('/', function(request, response){
  fs.readdir('./data', function(err, filelist){
    var title = 'Welcome';
    var description = 'Hello, Node.js';
    var list = template.list(filelist);
    var html = template.html(title, list,
      `<a href="/create">create</a>`,
      `<h2>${title}</h2>${description}`
    );
    response.send(html);
  });
});

// 2. pageId 링크 클릭 시 페이지
app.get('/page/:pageId', function(request, response){
  fs.readdir('./data', function(err, filelist){
    var filteredId = path.parse(request.params.pageId).base;
    fs.readFile(`data/${filteredId}`, 'utf8', function(err, description){
      var title = request.params.pageId;
      var sanitizedTitle = sanitizeHtml(title);
      var sanitizedDescription = sanitizeHtml(description);
      var list = template.list(filelist);
      var html = template.html(sanitizedTitle, list,
        `<a href="/create">create</a>
        <a href="/update/${sanitizedTitle}">update</a>
        <form action="/delete_process" method="post">
          <input type="hidden" name="id" value="${sanitizedTitle}">
          <input type="submit" value="delete">
        </form>
        `,
        `<h2>${sanitizedTitle}</h2>${sanitizedDescription}`);
      response.send(html);
    });
  });
});

//3. Create 버튼 클릭 시 페이지
app.get('/create', function(request, response){
  fs.readdir('./data', function(err, filelist){
    var title = 'WEB - create';
    var list = template.list(filelist);
    var html = template.html(title, list,
      '',
      `
      <form action="/create" method="post">
        <p><input type="text" name="title"
          placeholder="title">
        </p>
        <p>
          <textarea name="description"
          placeholder="description"></textarea>
        </p>
        <p><input type="submit"></p>
      </form>
    `);
    response.send(html);
  });
});

//4. create>제출 버튼 클릭 시 페이지
app.post('/create', function(request, response){
  var post = request.body;
  var title = post.title;
  var description = post.description;
  fs.writeFile(`data/${title}`, description, 'utf8',
  function(err) {
    response.redirect(`/page/${title}`);
  });
});

//5. update 버튼 클릭 시 페이지
app.get('/update/:pageId', function(request, response){
  fs.readdir('./data', function(err, filelist){
    var filteredId = path.parse(request.params.pageId).base;
    fs.readFile(`data/${filteredId}`, 'utf8', function(err, description){
      var title = request.params.pageId;
      var list = template.list(filelist);
      var html = template.html(title, list,
        //form 부분
        `
        <form action="/update" method="post">
          <input type="hidden" name="id" value=${title}>
          <p><input type="text" name="title"
            placeholder="title" value="${title}">
          </p>
          <p>
            <textarea name="description"
            placeholder="description">${description}</textarea>
          </p>
          <p><input type="submit"></p>
        </form>
        `,
        ``);
      response.send(html);
    });
  });
});

//6. update>제출 버튼 클릭 시 페이지
app.post('/update', function(request, response){
  var post=  request.body;
  var id = post.id;
  var title = post.title;
  var description = post.description;
  fs.rename(`data/${id}`, `data/${title}`, function(err){
    fs.writeFile(`data/${title}`, description, 'utf8',
    function(err) {
      response.redirect(`/page/${title}`);
    });
  });
})

//7. delete 버튼 클릭 시 페이지
app.post('/delete_process', function(request, response){
 var post = request.body;
  var id = post.id;
  var filteredId = path.parse(id).base;
  fs.unlink(`data/${filteredId}`, function(error){
    response.redirect('/');
  });
})
app.listen(port, () => console.log(`Example app listening at http://localhost:${port}`))
반응형