본문 바로가기

Back-End/Node.js

Express - 10. 미들웨어 만들기

반응형

목표

다른 이의 미들웨어를 사용하는 것이 아닌, 미들웨어 생산자가 되어 보자!

 


미들웨어 작성

 

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

Express 앱에서 사용하기 위한 미들웨어 작성 개요 미들웨어 함수는 요청 오브젝트(req), 응답 오브젝트 (res), 그리고 애플리케이션의 요청-응답 주기 중 그 다음의 미들웨어 함수 대한 액세스 권한�

expressjs.com

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

var myLogger = function (req, res, next) {
  console.log('LOGGED');
  next();
};

app.use(myLogger);

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

app.listen(3000);

app.use(함수)

var 함수 = function (req, res, next) {

  - req, res, next 객체

  - 함수 내부 구성에 따라 third-party middleware와 같은 기능을 가지게 된다.

 

미들웨어 사용

현재 우리의 코드에서 글 목록을 표현해주는 기능을 가진 readdir가 공통적으로 사용되고 있다. 이를 middleware로 처리를 해보자.

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

- next() : 다음에 호출되어야 할 middleware가 실행됨

이제 request.list에는 filelist가 담겨 있다.

// 2. pageId 링크 클릭 시 페이지
app.get('/page/:pageId', function(request, response){
  console.log(request.list);

pageId 클릭 시 request.list를 콘솔해보면 다음과 같이 filelist값이 들어가 있는 것을 확인할 수 있다.

request 객체에 list값을 셋팅하여 나온 결과이다. 이를 통해 이제 모든 라우트 안에서 request 객체의 list property를 통해 글 목록을 접근하게 된다. 따라서 각 경우의 수에서 일일이 파일을 readdir를 할 필요가 없다.

// 1. 홈 페이지
// app.get('/', (req, res) => {  res.send('Hello World!')})
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,
    `<a href="/create">create</a>`,
    `<h2>${title}</h2>${description}`
  );
  response.send(html);
});

readdir를 제거하고 파일이름을 request.list로 변경한다. 다른 코드들도 동일하게 변경한다.

 

문제점

하지만 이는 비효율적이다. 글 목록을 읽어올 필요가 없는 경우에도 글 목록을 무조건 읽어오기 때문이다. 

해결

app.get('*', function(request, response, next) {

app.use -> app.get 으로 수정한다.

그렇게 되면 get 방식으로 들어오는 요청만 파일 목록을 가져오게 된다. 그러면 기존의 post 방식은 파일 목록을 불러오지 않으므로 비효율적이라는 문제를 해결하게 된다.

check

//6. update>제출 버튼 클릭 시 페이지
app.post('/update', function(request, response){
  console.log(request.list);

위와 같이 작성하고 글을 update한 후 제출을 누르게 되면 다음과 같이 undefined라고 뜬다. 글 목록 데이터를 가져오지 않았다는 뜻이다. 따라서 우리가 만든 미들웨어를 이용하여 필요한 경우에만 파일 목록을 읽어온다.

 

코드 다시 살펴보기

여기서 우리가 작성한 코드를 다시 살펴보자.

// 1. 홈 페이지
// app.get('/', (req, res) => {  res.send('Hello World!')})
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,
    `<a href="/create">create</a>`,
    `<h2>${title}</h2>${description}`
  );
  response.send(html);
});

지금까지 라우트라고만 생각했던 이 코드에서 callback function은 사실 미들웨어였다. 우리가 이전에 만든 것처럼 말이다.

Express에서는 모든 것이 미들웨어로 이뤄져있다해도 과언이 아니다. 

app.use(bodyParser.urlencoded({ extended: false }));
app.use(compression());
app.get('*', function(request, response, next) {
  fs.readdir('./data', function(err, filelist){
    request.list = filelist;
    next();
  });
});

app.use를 통해 bodyParser 미들웨어가 실행이 되고, 그 다음 compression 미들웨어가 실행된 다음, 우리가 만든 미들웨어가 실행이 되고, 그 후 순서대로 아래로 쭉 실행되다가 path에 해당하는 미들웨어가 실행된다.

미들은 가운데라는 뜻이다. 애플리케이션이 구동될 때 순서대로 등록된 프로그램들이 실행이 되는데, 각각 프로그램들이 서로가 서로를 연결해주는 작은 소프트웨어라는 점에서 미들웨어라는 표현을 사용한다.

 

전체 코드

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;
const compression = require('compression');

app.use(bodyParser.urlencoded({ extended: false }));
app.use(compression());
//파일목록읽는 미들웨어 만들기
app.get('*', function(request, response, next) {
  fs.readdir('./data', function(err, filelist){
    request.list = filelist;
    next();
  });
});

// 1. 홈 페이지
// app.get('/', (req, res) => {  res.send('Hello World!')})
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,
    `<a href="/create">create</a>`,
    `<h2>${title}</h2>${description}`
  );
  response.send(html);
});

// 2. pageId 링크 클릭 시 페이지
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);
    var list = template.list(request.list);
    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){
  var title = 'WEB - create';
  var list = template.list(request.list);
  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){
  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 부분
      `
      <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}`))

 

 

반응형