Node.js

App - 글수정 - 수정된 내용 저장

수업소개

전송된 수정 내용을 받아서 파일명을 변경하고, 내용을 저장하는 방법을 알아봅니다.

 

 

 

강의

 

 

 

소스코드

main.js (변경사항)

var http = require('http');
var fs = require('fs');
var url = require('url');
var qs = require('querystring');

function templateHTML(title, list, body, control){
  return `
  <!doctype html>
  <html>
  <head>
    <title>WEB1 - ${title}</title>
    <meta charset="utf-8">
  </head>
  <body>
    <h1><a href="/">WEB</a></h1>
    ${list}
    ${control}
    ${body}
  </body>
  </html>
  `;
}
function templateList(filelist){
  var list = '<ul>';
  var i = 0;
  while(i < filelist.length){
    list = list + `<li><a href="/?id=${filelist[i]}">${filelist[i]}</a></li>`;
    i = i + 1;
  }
  list = list+'</ul>';
  return list;
}

var app = http.createServer(function(request,response){
    var _url = request.url;
    var queryData = url.parse(_url, true).query;
    var pathname = url.parse(_url, true).pathname;
    if(pathname === '/'){
      if(queryData.id === undefined){
        fs.readdir('./data', function(error, filelist){
          var title = 'Welcome';
          var description = 'Hello, Node.js';
          var list = templateList(filelist);
          var template = templateHTML(title, list,
            `<h2>${title}</h2>${description}`,
            `<a href="/create">create</a>`
          );
          response.writeHead(200);
          response.end(template);
        });
      } else {
        fs.readdir('./data', function(error, filelist){
          fs.readFile(`data/${queryData.id}`, 'utf8', function(err, description){
            var title = queryData.id;
            var list = templateList(filelist);
            var template = templateHTML(title, list,
              `<h2>${title}</h2>${description}`,
              `<a href="/create">create</a> <a href="/update?id=${title}">update</a>`
            );
            response.writeHead(200);
            response.end(template);
          });
        });
      }
    } else if(pathname === '/create'){
      fs.readdir('./data', function(error, filelist){
        var title = 'WEB - create';
        var list = templateList(filelist);
        var template = templateHTML(title, list, `
          <form action="/create_process" 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.writeHead(200);
        response.end(template);
      });
    } else if(pathname === '/create_process'){
      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.writeHead(302, {Location: `/?id=${title}`});
            response.end();
          })
      });
    } else if(pathname === '/update'){
      fs.readdir('./data', function(error, filelist){
        fs.readFile(`data/${queryData.id}`, 'utf8', function(err, description){
          var title = queryData.id;
          var list = templateList(filelist);
          var template = templateHTML(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?id=${title}">update</a>`
          );
          response.writeHead(200);
          response.end(template);
        });
      });
    } else if(pathname === '/update_process'){
      var body = '';
      request.on('data', function(data){
          body = body + data;
      });
      request.on('end', function(){
          var post = qs.parse(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: `/?id=${title}`});
              response.end();
            })
          });
      });
    } else {
      response.writeHead(404);
      response.end('Not found');
    }
});
app.listen(3000);

 

 

 

 

수업에서 다루지 못한 이야기

pm2를 실행할 때 --watch 옵션을 주면 파일이 변경되었을 때 앱을 리로드하게 됩니다. 즉 data 디렉토리의 파일이 수정되었을 때 리로드가 일어나게 되는 것이죠. 이런 문제를 방지하기 위해서는 data 디렉토리에 대해서는 watch를 하지 않도록 설정해야 합니다. 아래의 방법이 도움이 될 것입니다. 

pm2 delete main
pm2 start main.js --watch --ignore-watch="data/*"

 

댓글

댓글 본문
  1. 남이
    한글로 업데이트 및 생성 안되는 것에 대하여,

    response.writeHead(302, {Location: encodeURI(`/?id=${title}`)});

    location 에 대한 값을 encodeURI() 내부에 넣어 보시길 바랍니다.

    저는 이렇게 수정하고 정상 작동합니다.
  2. 남이
    안녕하세요. 질문 남겨봅니다.
    Create, Update 할때 title 값에다가 '?'를 넣고 끝냈을때 (ex. 'what is this?') Create 혹은 update 할때 description 항목이 undefined 로 웹에 뜨지만, code editor 에서는 파일이 저장 및 수정되지 않습니다(VSCODE 사용중). PM2 logs 로 확인해봐도 에러가 잡히는 게 없어요.
    console.log 로 찍어보니 post 값까지는 제대로 넘어옵니다.

    ex)
    0|main | [Object: null prototype] {
    0|main | title: 'what is this?',
    0|main | description: 'what do you mean?'
    0|main | }

    반대로, 타이틀값은 '?' 문자를 제거하고 description 에는 마지막을 '?'로 끝냈을 때 정상적으로 파일이 저장 및 수정됩니다.
    ex)
    title: 'what',
    description: 'what is this??'

    이 문제에 대해 아시는 분 계시면 알려주시면 감사하겠습니다.
  3. Jeong Il Haan
    20210421
  4. byoonn
    완료
  5. 21.02.27
  6. chimhyangmoo
    21.02.24
  7. jeisyoon
    2021.02.11 App - 글수정 - 수정된 내용 저장 완료
  8. 마아앙
    2021.02.09
  9. 뭄수
    완료
  10. ohhigo
    21/1/24 ★★★★★
  11. 2021.01.06 완료!
  12. 손민철
    20/12/31 완료
  13. 생활둘기
    2020 12 26
  14. kkn1125
    20.12.22 완료~!
  15. 옹옹
    재밌습니다!
  16. 너구친구
    와우 감탄 나오네요 쉽고 효율적인 설명 감사합니다.
  17. Juveloper
    갈수록 어려워지고 복잡해지네요..ㅜㅜ 여기까지 복습해봐야겠습니다!
  18. 콜라
    20201015 완료
  19. Yong Hyun Lee
    완료 201002
  20. 2020.09.10
  21. 김지민
    이미 알아차리셨을 수도 있지만 의견 공유해봅니다!
    writeFile 함수를 rename의 callback 함수로 썼느냐 안썼느냐의 차이인거 같습니다.
    만약 vocalyc님의 코드로 실행된다면 네트워크 상의 문제 등으로 rename 함수에서 error가 난다 해도 rename만 되지 않을 뿐 writeFile 함수는 실행될 수 있고 data 디렉토리 안에 wirteFile로 인한 파일이 따로 생겨날 수 있죠. 예제에서의 CSS 파일 update가 아니라 CSS3 파일이 create 될 것입니다
    하지만 영상처럼 callback 함수로 쓴다면 error가 아닐 경우 wirteFile 함수를 호출하는 것이기 때문에 error로 인해 rename이 되지 않으면 writeFile 즉, 갱신도 되지 않는거죠
    대화보기
    • Jenny Song
      30th.JULY.2020 완료

      write.File() 사용하면 그냥 그 rename한 제목과 동일한 제목을 가진상태로 decription만 내용으로 하는 파일이 새로 생기는것 아닌가?
      /create 에서 한것처럼, 파일명과 내용 입력하면 해당 파일이 새로 생성되는 것 처럼.
      어째서 새로 생성되지 않고 기존 파일에 덮어씌어지는 것일까??
    • 영호팍
      긋긋~~~ 출석 완료요~~
    • Amousk
      좋은 강의 감사합니다.
    • Katherine Roh
      rename이 동작은 하는데, 수정된 파일명으로 새로운 파일이 생기기만 하고,
      원래 파일은 삭제되지 않고 그대로 있습니다.
      test1 파일을 test2로 수정하면,
      test1과 test2 파일 두 개가 같이 있어요.
    • 김재익
      완료
    • 김보미
      완료
    • 바다의왕자
      완료
    • 소종원
      그 함수 두개는 그 상단의 함수 request.on의 아래 단에 위치하고 있습니다. 그리고 그 함수보다 위에 id와 title, description들을 정의했고요 이 정의한 값들을 a라고 임의의 명칭으로 지정했을 때 이렇게 했을때 rename함수 안에 write함수를 작성하지 않을 경우, 두 함수에서 쓰이는 id와 title, description은 값이 a가 됩니다. 반면 rename함수 안에 write을 작성했을 경우 만약 rename에서 id와 title, description을 다르게 정의했다면 이 값을 b라고 쳤을 때 rename함수 안에 있는 write함수는 이 b값을 가지고 사용하는 겁니다. 말이 좀 복잡하게 됐는데, 간단하게 말해서 rename에서 변경한 값들을 공유해서 write함수에서 사용하기 위해 rename함수 안에 작성하는 겁니다. 이걸 이해하기 위해서는 전역변수와 지역변수의 개념을 알아야 합니다.
      대화보기
      • vocalyc
        선생님이 만드신
        fs.rename(`data/${id}`, `data/${title}`, function(error){
        fs.writeFile(`data/${title}`, description, 'utf8', function(err){
        response.writeHead(302, {Location: `/?id=${title}`});
        response.end();
        })
        });
        이 코드는 파일 제목을 바꾸는 함수 안에 파일 내용을 바꾸는 함수가 들어가 있습니다.
        하지만 저는
        fs.rename(`data/${id}`, `data/${title}`, function(err){

        });
        fs.writeFile(`data/${title}`, description, 'utf8',
        function(err){
        response.writeHead(302, {Location:
        `/?id=${title}`});
        response.end();
        });
        이렇게 제목을 바꾸는 함수 바깥쪽에 내용을 바꾸는 함수를 해도 똑같이 작동을 하는데 혹시 제목을 바꾸는 함수 안에 내용을 바꾸는 함수가 꼭 들어가야 하는 이유가 있을까요?
        아니면 둘다 상관이 없는건가요?
      • 윤영훈
        감사합니다!
      • 다시듣기
      • rediretion 고민자
        파일명이 한글일 경우에 TypeError [ERR_INVALID_CHAR]: Invalid character in header content ["Location"]
        라고 뜨는데 해결하려면 어떻게 해야할까요? ?

        파일명이 영문, 숫자로 이뤄졌을때는 update_process 의 redirection이 잘 됩니다.
      • 준바이
        감사합니다.
      • 심여수
        감사합니다
      • 03.11 완료
      • eddylee123456
        복습
      • Dave Lee
        검색하세요...
      • ㄳㅎ
        제목을 한글로 지을시 왜 리다이렉션이 안되는걸까요???!!
      • ㄱㅎㅈ
        pm2 start main.js --watch --ignore-watch="data/*"
        명령프롬프트에 입력하면 잘 작동합니다.
      • 스티븐잡숴
        완료
      • 매리미
        pm2 delete main 은 뭐죠..? pm2가 main.js의 변경을 감시하는걸 중단시키는 명령인가요?
      • 임은정
        완료
      • codinginpain
        완료했읍니다다다닷!!
      • 강다리
        run
      • 쑤우
        수강완료. 감사합니다~
      • 굼벵이
        완료
      • morning
        pm2 start main.js --watch --ignore-watch="data/*" 이게 꼭 필요하군요.. nginx 에서 upstream 이용해서 포트를 바꿔서 node js에 넘겨주는데 계속 502 에러가 나서 한참 구글링 헤매다가 정작 "수업에서 다루지 못한 이야기"는 보지 못했네요.

        /var/log/nginx/error_log
        *76 recv() failed (104: Connection reset by peer) while reading response header from upstream, client: 192.168.0.4, server: _, request: "GET /?id=new HTTP/1.1", upstream: "http://192.168.0.10:3000/?id=new", host: "192.168.0.10", referrer: "http://192.168.0.10/update?id=new"
      • 박호용
        윈도우 10에서 VScode로 테스트 중입니다.
        rename 하는 과정에서 오류가 발생합니다.
        errno 는 -4058 인데 왜 그럴까요
      • CronEB
        완료
      버전 관리
      egoing
      현재 버전
      선택 버전
      graphittie 자세히 보기