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. codinginpain
    완료했읍니다다다닷!!
  2. 강다리
    run
  3. 쑤우
    수강완료. 감사합니다~
  4. 굼벵이
    완료
  5. 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"
  6. 박호용
    윈도우 10에서 VScode로 테스트 중입니다.
    rename 하는 과정에서 오류가 발생합니다.
    errno 는 -4058 인데 왜 그럴까요
  7. CronEB
    완료
  8. YesterdayKite
    완료. 감사합니다!
  9. Stephen Lee
    이상한 점을 발견했는데요 리스트중 아무거나 클릭한 후(예를 들어 html) update 를 누르고 element 탭에 들어가면 input type 이 hidden 인 element 의 value 가 html 인 것을 확인하실 수 있습니다. 이를 리스트에 없는 이름으로 바꾼후(예를 들어 html2) 그다음 description 도 아무렇게나 바꿔준후, submit 을 누를시 새로운 파일이 생성됩니다. 마치 create_process 영역의 로직처럼 실행됩니다. 제 생각에는 fs.rename 로직을 만났을때 old path 에 들어갈 값이 없으므로 에러가 발생해 실행이 멈춰야 된다 생각하지만 callback 로직이 실행돼 fs.writeFile 로 새로운 파일을 만들고 있습니다.

    err 에 대한 처리가 없으니 err 가 발생해도 callback 이 그대로 실행되고 writeFile 이 실행돼 새로운 파일을 만든다는 것을 알게 됐네요(err 가 있을시 console 로 에러를 찍으라 했더니 log 가 찍혔습니다.) 그리고 마찬가지로 리스트에 이미 존재하는 이름으로 hidden input 에 값을 주었을때 해당 파일이 바뀌니 fs.writeFile 은 경로가 있으면 파일을 업데이트하고 없으면 새로생성하는 것이 맞는건가요?
  10. Stephen Lee
    writeFile() 은 첫번째 변수에 경로를 넣어주는데 해당 경로가 없으면 새로 file을 만드는 건가요? 만약 해당 경로가 있다면 그 파일을 수정하는 것인지 궁금합니다.
    단지 writeFile() 이 새로운 파일을 생성하는것이라면 rename 한 css 는 css3 가 되고 css3 라는 이름을 가진 새로운 다른 파일이 생성되는게 아닌가 하는 의문이 듭니다.
  11. youngjin.lee
    completed
  12. 허공
    190510 감사합니다.
  13. 위준우
    완료
  14. 자유로움
    완료
  15. title이 공백문자를 포함하고있는 경우 수정 페이지에 들어갔을시에 첫번째 공백문자 뒤로는 문자가 나오지 않는데 이 문제는 어떻게 해결해야하나요?
  16. supernet
    감사합니다.
  17. 호두
    고맙습니다.
  18. 권문수
    완료!! 감사합니다^^
  19. jo_onc
    "서식을 준 형태로 글을 저장" 질문이 이해가 잘 가지 않는데,
    만약 서식이,
    1.디자인(사이즈, 컬러 등)을 말씀하시는 거라면 'CSS'를 알아보시고,
    2.값을 말씀하시는 거라면 파일의 데이터 값을 알아보시면 됩니다!
    대화보기
    • JongHun Cha
      pm2 start main.js --watch --ignore-watch="data/*"

      상기 방법이 잘 적용이 되지 않습니다.
      명령어를 입력하여도 main.js나 data 디렉토리 안의 폴더를 변경하거나 앱상에서 생성 및 변경을 할 때 모두
      앱을 리로드 합니다.. --watch 명령어가 --ignore를 오버라이드 하지 않나 생각이듭니다.

      만약 아래와 같이 좀더 구체적으로 watch의 경로를 지정해주면 명령어가 적용됩니다.
      pm2 start main.js --watch="main.js" --ignore-watch="data/*"

      하지만 이렇게 구체적인 경로를 지정하기 어려우므로,
      pm2 ecosystem 으로 ecosystem.config.js 파일 생성후 아래와 같은 형식으로 내용 변경 후
      pm2 start ecosystem.config.js 를 실행하면 잘 됩니다.
      하지만... 혹시 그냥 저렇게 단순한 명령어로 잘 실행이 되도록 다른 방법이 있다면 답변 부탁드려용~ ㅠ

      module.exports = {
      apps :
      {
      name : 'main',
      script : 'main.js',
      watch : true,
      ignore_watch : ["data/*"],
      exec_mode : "cluster",
      instances : 1,
      merge_logs : true,
      log_date_format : "YY-MM-DD HH:mm:ss",
      error_file : "./logs/err.log",
      out_file : "./logs/out.log"
      }
      };
    • Kyoungil Lee
      이번 예제에서 헤깔릴수 있는 부분이

      fs.rename(`old_path`,`new_path`,function(error){
      fs.writeFile(`new_path`,description,'utf8',function(error){
      response.writeHead(302,{location: `/?id=${title}`});
      response.end('update success!');
      });
      });

      여기서 fs.rename 메소드가 이 fs.writeFile 메소드 보다 먼저 실행됩니다.
      때문에 fs.writeFile에서 new_path를 삽입해 주어야합니다.

      fs.writeFile 윗줄에다

      fs.readdir(`./data`,function(err,filelist){ console.log(filelist); } );

      이줄을 넣어서 실행시켜보시면 확실하게 알 수 있습니다.
    • 삼고잉
      첫번째 훑기
    • Gimme_Gsuit
      rename 함수???를 사용하면서 업데이트시 바뀐 title, description 값으로 수정하게 됩니다.(미사용시 기존에 있던 값들을 그대로 두고 바뀐 값들을 추가 하게 되는 경우도 확인 되었습니다.) 감사합니다.
    • 저는 update_process 에서 변수로 선언한 body가
      위에 create_process내 에서 선언한 body랑 충돌이나는데
      왜 그러는 걸까요....ㅠㅠ
    • moon
      감사합니다.
    • Seo Yun Seok Tudoistube
      TextArea 안에 서식을 준 형태로 글을 저장하려면 뭘 알아야 할지 궁금합니다.
      감사합니다!
    버전 관리
    egoing
    현재 버전
    선택 버전
    graphittie 자세히 보기