본문 바로가기

Back-End/Node.js

Express - 13. 에러처리

반응형

목표

에러처리하는 방법 알기

 


1. 존재하지 않는 페이지를 찾았을 때 발생하는 에러 (404)

http상에서는 404 Not found 에러를 보내주기로 약속되어 있다.

Google에 express 404 검색해보자.

 

Express 자주 묻는 질문(FAQ)

자주 묻는 질문(FAQ) 애플리케이션을 어떻게 구조화해야 합니까? 이 질문에는 정확한 답이 없습니다. 그 답은 애플리케이션의 규모 및 참여하는 팀의 규모에 따라 달라질 수 있습니다. 최대한의 �

expressjs.com

즉, 코드 아래에 다음 코드를 추가해준다. 이 코드는 미들웨어이다.

미들웨어는 순차적으로 실행된다. 이 코드를 마지막인 app.listen위에 작성하게 되면 위의 작성한 path들을 못찾고 그외의 주소에 접근한 경우이다. 그때 404 status를 보내주고, 찾을 수 없다는 메세지를 보낸다.

 

2. 없는 페이지에 접근 시 에러 발생시키기

없는 페이지에 접근한 경우 에러가 발생되어야하는데 위와 같이 page/페이지명 을 입력한 경우 에러가 발생하지 않는다. 그 이유는 아래와 같다.

// 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);
  });
});

readFile을 하여 파일을 읽은 후, 접근한 파일이름이 없는 경우 콜백함수의 err객체에 에러가 전달된다. 하지만 에러가 있는 경우를 다뤄주지 않았기 때문에 위와 같은 문제가 발생하는 것이다.

// 2. pageId 링크 클릭 시 페이지
app.get('/page/:pageId', function(request, response, next){
  var filteredId = path.parse(request.params.pageId).base;
  fs.readFile(`data/${filteredId}`, 'utf8', function(err, description){
    if(err){
      next(err);
    }else{
      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);
    }
  });
});

에러가 발생한 경우 next(err)가 실행되고, 에러가 실행되지 않은 정상적인 접근의 경우 else로 원래 코드가 실행이 된다.

next(err)를 통해 에러 데이터를 전송해준다.

이제 없는 페이지에 접속한 경우에 에러가 발생하게 된다. 만약 출력되는 정보를 바꾸고 싶다면, 아래를 보자.

 

에러 페이지 출력 변경하기

 

Express 오류 처리

오류 처리 다른 미들웨어 함수와 동일반 방법으로 오류 처리 미들웨어 함수를 정의할 수 있지만, 오류 처리 함수는 3개가 아닌 4개의 인수, 즉 (err, req, res, next)를 갖는다는 점이 다릅니다. 예를 ��

expressjs.com

처음에 추가한 404에러 코드 아래에 추가한다.

4개의 인자를 가진 함수는 error를 핸들링하기 위한 미들웨어로 약속되어 있다.

 

따라서 만약 페이지를 찾을 수 없는 경우 next(err)가 다음에 등록된 모든 미들웨어를 무시하고 제일 마지막에 있는, 우리가 방금 추가한 미들웨어로 이동하여 첫 번째 인자인 err로 전달하고 실행하게 된다.

결과

 

전체 코드

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(express.static('public'));
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}
    <img src="/images/hello.jpg" style="width:300px"; display:block; margin-top: 10px;>`
  );
  response.send(html);
});

// 2. pageId 링크 클릭 시 페이지
app.get('/page/:pageId', function(request, response, next){
  var filteredId = path.parse(request.params.pageId).base;
  fs.readFile(`data/${filteredId}`, 'utf8', function(err, description){
    if(err){
      next(err);
    }else{
      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){
  console.log(request.list);
  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.use(function(req, res, next){
  res.status(404).send('sorry cant find that!');
});

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

app.listen(port, () => console.log(`Example app listening at http://localhost:${port}`))
반응형