ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [생활코딩] Node.js 강의 12일차 (Web3-Express)
    Node.js 2021. 7. 2. 18:26

    Express 미들웨어의 사용 - body parser

    Express의 중요한 기능은 1. 라우트 2.미들웨어 , 이 두가지가 있다. 

    미들웨어란? 서비스를 운영체계 상관없이 애플리케이션에 제공하는 소프트웨어이다. 

    Middleware is a type of computer software that provides services to software applications beyond those available from the operating system  (Wikipedia) 

    쉽게 이야기해보자. 소프트웨어를 만들때 처음부터 끝까지 다 만드는 경우는 거의 없다. 미들웨어는 다른 사람이 만든 소프트웨어를 부품으로 쓸 수 있게 해준다. 정확한 정의는 아니지만, 다른 사람이 만든 소프트웨어를 미들웨어라고 치자. Third-party middleware는 express가 공식적으로 만들지 않고 다른 사람이 만든 미들웨어라는 뜻이다.  

     

    수업에서는 body-parser라는 미들웨어를 사용해봤다. (http://expressjs.com/en/resources/middleware/body-parser.html)

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

       body-parser  : 그 본체인 데이터를 분석해서 필요한 형태로 가공해주는 프로그램

     

    일단 body-parser가 설치가 됐는지 확인해주고 시작하겠다. 

    npm show body-parser version 

    설치가 안됐다면

    npm install body-parser --save

     body-parser  main.js에 적용 

    app.use() 이 괄호 안은 body-parser가 만들어낸 미들웨어를 표현한다.  main.js가 실행될때마다 괄호안의 미들웨어가 실행된다. body-parser는 사용자가 전송한 post 데이터를 내부적으로 분석해서 모든 데이터를 가지고 온 다음에 create_process, update_process, delete_process 각 라우터에 해당되는 callback 함수를 호출한다. 그렇게 약속됐다. 호출하면서 callback 함수의 첫번째 인자인 request 에 body property를 만들어준다. (원래 request에는 body property는 없었다.) 

     

    var express = require('express')
    var app = express()
    var bodyParser = require('body-parser');
    
    /*생략*/
    app.post('/create_process',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(`/?id=${title}`);
      })
      /* 이전 코드
      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(`/?id=${title}`);
        })
      });
      */ 
    });
    
    /*생략*/

    Express 미들웨어의 사용 - compression

    compression 설치가 됐는지 확인해주고 시작하겠다. (http://expressjs.com/en/resources/middleware/compression.html)

    npm show compression version 

    설치가 안됐다면

    npm install compression --save

     compression main.js 적용 

    compression을 호출하면 미들웨어를 리턴하도록 약속되었고, 이 미들웨어가 app.use로 장착된다. 그러면 우리 애플리케이션은 요청이 들어올때마다 body parser 미들웨어가 호출되고 compression 미들웨어가 실행되길 약속되었다.

    var express = require('express')
    var app = express()
    var fs = require('fs');
    var path = require('path');
    var sanitizeHtml =require('sanitize-html');
    var bodyParser = require('body-parser');
    var compression = require('compression');
    var template = require('./lib/template.js');
    var qs = require('querystring');
    
    app.use(bodyParser.urlencoded({extended:false}));
    app.use(compression());
    
    /*생략*/

    (강제로 리로드 -  윈도우: ctrl +shift +R / 맥 : cmd+shift+R)

    compression이 적용되고 원래 33.3 kB가 4.9kB 로 압축돼 네트워크에 전송되는것을 확인할 수 있다. 

    compression 적용 결과


    Express 미들웨어 만들기

    폴더에서 파일을 읽어오는 아래 코드가 곳곳에서 사용돼 미들웨어로 만들어주는 작업을 했다. 

    fs.readdir('./data',function(error,filelist){/*생략*/});

    먼저 app.use로 요청이 들어올때마다 수행하는 코드를 작성해봤다. 

    app.use(function(request,response,next){
      fs.readdir('./data',function(error,filelist){
        request.list =filelist;
        next(); 
      });
    });

    하지만 post 방식인, create_process, update_process, delete_process에는 위 코드가 필요가 없다. 그럼 안읽어주는게 효율적이기에 get방식인 라우터만 적용되게 코드를 바꿔줬다. 

    app.get('*',function(request,response,next){
      fs.readdir('./data',function(error,filelist){
        request.list =filelist;
        next(); 
      });
    });

    위 코드와 아래코드를 비교해보면, app.get의 두번째 인자는 미들웨어라는 것을 알 수 있다. Express에서는 모든게 middleware라고 할 수 있다. 

    app.get('/', function(request, response){
      var title = 'Welcome';
      var description  = 'Hello Node.js'
      var list = template.list(request.list);
      var html = template.html(title,list,`<h2>${title}</h2>${description}`,
      `<a href ="/create">create</a>`);
      response.send(html);
    });

    애플리케이션이 구동될때, 순서대로 등록된 작은 프로그램들이 실행되고 각각의 프로그램들이 서로서로 연결해주는 작은 소프트웨어라는 점에서 'middleware'라는 표현을 쓰는 듯하다. 


    Express 미들웨어의 실행순서

    우리가 만든 미들웨어는 Application-level middleware 강의에서는 이것만 다룸,  더 자세한 내용은 여기서 확인하자.

    app.use(함수)를 작성하면 미들웨어가 등록된다. 미들웨어의 핵심은 request와 response 객체를 받아서 변형할 수 있다. next라는 함수를 호출해서 다음에 실행되어야할 미들웨어실행할지 실행하지 않을지 , 그 미들웨어의 이전 미들웨어가 결정하도록 한다는 것이 핵심이다. 

    var app = express()
    
    app.use(function(req,res,next){
    	console.log('Time:'.Date.now())
        next()
    })

    미들웨어가 여러개 등록될수있다. 1번함수가 실행되고 next를 호출하면, 2번함수를 호출하는 것과 다름 없음. 순서대로 실행됨.

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

    조건문을 통해 처리할 수도 있다. user ID가 0이면 다음 라우트 3번이 실행되고, 아니라면 같은 라우트 안의 2번이 실행된다. 

    app.get('/user/:id', /*1번*/function (req, res, next) {
      // if the user ID is 0, skip to the next route
      if (req.params.id == 0) next('route');
      // otherwise pass the control to the next middleware function in this stack
      else next(); //
    }, /*2번*/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',/*3번*/ function (req, res, next) {
      res.render('special');
    });
    

    강의 코드

    var express = require('express')
    var app = express()
    var fs = require('fs');
    var path = require('path');
    var sanitizeHtml =require('sanitize-html');
    var bodyParser = require('body-parser');
    var compression = require('compression');
    var template = require('./lib/template.js');
    var qs = require('querystring');
    
    app.use(bodyParser.urlencoded({extended:false}));
    app.use(compression());
    
    app.get('*',function(request,response,next){
      fs.readdir('./data',function(error,filelist){
        request.list =filelist;
        next(); 
      });
    });
    
    app.get('/', function(request, response){
      var title = 'Welcome';
      var description  = 'Hello Node.js'
      var list = template.list(request.list);
      var html = template.html(title,list,`<h2>${title}</h2>${description}`,
      `<a href ="/create">create</a>`);
      response.send(html);
    });
    
    app.get('/page/:pageId', function(request, response){
      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,{
          allowedTags:['h1']
        });
        var list = template.list(request.list);
        var html= template.html(title,list,`<h2>${sanitizedTitle}</h2>${sanitizedDescription}`,
        `<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>`);
        response.send(html);
      });
    });
    
    app.get('/create',function(request,response){
      var title = 'Web - create';
      var list = template.list(request.list);
      var html = template.html(title,list,`
      <form action="/create_process" method="post">
        <p><input type="text" name="title" placeholder="text"></p>
        <p>
          <textarea name="description" placeholder="description"></textarea>
        </p>
        <p>
          <input type="submit">
        </p>
      </form>
      `,'');
      response.send(html);
    
    });
    
    app.post('/create_process',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(`/?id=${title}`);
      })
    
    });
    
    app.get('/update/:pageId', function(request, response){
      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(request.list);
        var html = template.html(title, list,
          `
          <form action="/update_process" 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>
          `,
          `<a href="/create">create</a> <a href="/update/${title}">update</a>`
        );
        response.send(html);
      });
    });
     
    app.post('/update_process', 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(error){
        fs.writeFile(`data/${title}`, description, 'utf8', function(err){
          response.writeHead(302, {Location: `/page/${title}`});
          response.end();
        });
      });
    
    });
    
    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(3000, function(){
      console.log('Example app listening on port 3000!')
    });
Designed by Tistory.