생활코딩 - Node.js

iamokian·2023년 5월 22일
0

Nodejs

목록 보기
1/1
post-thumbnail

*생활코딩 - Node.js를 보고 내용 정리하기

1. 웹서버 만들기

👩‍💻

var http = require('http');
var fs = require('fs');
var app = http.createServer(function(request,response){
    var url = request.url;
    if(request.url == '/'){
      url = '/index.html';
    }
    if(request.url == '/favicon.ico'){
      return response.writeHead(404);
    }
    response.writeHead(200);
    response.end(fs.readFileSync(__dirname + url));
 
});
app.listen(3000);

위 코드는 Node.js에서 작동하는 간단한 웹 서버를 생성하는 코드이다. 이 서버는 HTTP 모듈을 사용하여 요청을 처리하고, 파일 시스템 모듈(fs)을 사용하여 파일을 읽어 클라이언트에게 응답한다.

이 코드에서는 require 함수를 사용하여 http 모듈과 fs 모듈을 가져온다. http 모듈은 웹 서버를 생성하고, fs 모듈은 파일을 읽는데 사용된다.

그리고 http.createServer() 함수를 사용하여 서버를 생성한다. 이 함수는 콜백 함수를 인자로 받는다. 이 콜백 함수는 요청(request)과 응답(response)매개변수를 가지며, 클라이언트의 요청에 대한 응답을 처리한다.

콜백 함수에서는 먼저 request.url을 검사하여 클라이언트가 요청한 URL을 확인한다. 만약 요청한 URL이 / 인 경우 url 변수를 /index.html 로 설정한다. 이는 기본 페이지로 사용 될 index.html 파일을 의미한다.

그 다음 /favicon.ico 를 요청한 경우, 404 상태 코드를 반환하고 함수를 종료한다. 이는 웹 브라우저가 파비콘을 요청하는 경우이다.

그 외의 모든 요청에 대해서는 200 상태 코드를 반환하고 fs.readFileSync() 함수를 사용하여 해당 파일을 동기적으로 읽은 후에 응답(response)으로 보낸다.__dirname + url 은 현재 실행 중인 스크립트 파일의 디렉토리와 요청한 URL을 조합하여 파일의 경로를 생성한다.

마지막으로, app.listen(3000) 을 호출하여 서버를 3000번 포트에서 실행한다. 이제 웹 서버가 해당 포트에서 요청을 대기하고 클라이언트에게 파일을 제공할 수 있다.


2. URL로 입력된 값 사용하기

🖍 URL 이해하기

url 예시)

http://opentutorials.org:3000/main?id=HTML&page=12

  • http
    protocol 통신규칙, 사용자가 서버에 접속할 때 어떤방식으로 통신할 것인가에 대한 부분. 웹브라우저와 웹서버가 서로 데이터를 주고받기 위해서 만든 통신 규칙, 만약 FTP를 사용한다면 이 부분은 FTP가 된다.

  • opentutorials.org
    host(domaim), 인터넷에 접속되어 있는 각각의 컴퓨터.

  • 3000
    port(포트번호). 한대의 컴퓨터안에 여러대의 서버가 있을 수 있다. 이럴 경우 클라이언트가 접속 했을 때 어떤 서버와 통신할지 애매하다. 그래서 접속할 때 포트번호를 지정해 그 포트번호와 연결된 서버에 접속하게 된다.

  • main
    path. 컴퓨터안에 있는 어떤 디렉토리의 어떤 파일인지를 가리킨다.

  • id=HTML&page=12
    quert string. 이 값을 변경하면 웹서버에게 데이터를 전달 할 수 있다. 그리하여 query string 앞에는 '?'가 붙고 값과 값은 '&'를 쓰기로 약속되어 있고 값의 이름과 값은 '='로 구분하기로 약속되어 있다.

👩‍💻

var http = require('http');
var fs = require('fs');
var url = require('url');
 
var app = http.createServer(function(request,response){
    var _url = request.url;
    var queryData = url.parse(_url, true).query;
    console.log(queryData.id);
    if(_url == '/'){
      _url = '/index.html';
    }
    if(_url == '/favicon.ico'){
      return response.writeHead(404);
    }
    response.writeHead(200);
    response.end(queryData.id);
 
});
app.listen(3000);

위 코드에서는 요청한 URL을 통해 입력된 값을 사용할 수 있도록 코드가 추가되었다.

url 모듈은 URL 파싱에 사용된다.

parse() : URL 문자열을 입력하면 URL 객체를 만든다. 'format()'의 반대

request.url 을 통해 클라이언트가 요청한 URL을 가져온다. url.parse 함수를 사용하여 URL을 파싱하고, query 객체에서 id 속성을 가져온다. queryData.id 는 URL 쿼리 문자열에서 id라는 이름의 매개 변수의 값을 나타낸다.

http://localhost/?id=HTML

위 코드와 같이 입력한다면 id 값은 HTML이 된다.


3. 동적인 웹페이지 만들기

👩‍💻

var http = require('http');
var fs = require('fs');
var url = require('url');
 
var app = http.createServer(function(request,response){
    var _url = request.url;
    var queryData = url.parse(_url, true).query;
    var title = queryData.id;
    if(_url == '/'){
      title = 'Welcome';
    }
    if(_url == '/favicon.ico'){
      return response.writeHead(404);
    }
    response.writeHead(200);
    var template = `
    <!doctype html>
    <html>
    <head>
      <title>WEB1 - ${title}</title>
      <meta charset="utf-8">
    </head>
    <body>
      <h1><a href="/">WEB</a></h1>
      <ul>
        <li><a href="/?id=HTML">HTML</a></li>
        <li><a href="/?id=CSS">CSS</a></li>
        <li><a href="/?id=JavaScript">JavaScript</a></li>
      </ul>
      <h2>${title}</h2>
      <p><a href="https://www.w3.org/TR/html5/" target="_blank" title="html5 speicification">Hypertext Markup Language (HTML)</a> is the standard markup language for <strong>creating <u>web</u> pages</strong> and web applications.Web browsers receive HTML documents from a web server or from local storage and render them into multimedia web pages. HTML describes the structure of a web page semantically and originally included cues for the appearance of the document.
      <img src="coding.jpg" width="100%">
      </p><p style="margin-top:45px;">HTML elements are the building blocks of HTML pages. With HTML constructs, images and other objects, such as interactive forms, may be embedded into the rendered page. It provides a means to create structured documents by denoting structural semantics for text such as headings, paragraphs, lists, links, quotes and other items. HTML elements are delineated by tags, written using angle brackets.
      </p>
    </body>
    </html>
    `;
    response.end(template);
 
});
app.listen(3000);

queryData.id 값을 title 변수에 저장한다. 이 값은 URL의 'id' 쿼리 매개 변수의 값을 나타내고, _url/ 인 경우 titleWelcome 으로 설정한다.

template 변수에는 HTML코드를 담았다. 이 HTML 코드는 서버가 클라이언트에게 반환하는 응답의 본문이다.

  • ${title} 은 변수 title 의 값을 출력한다.

response.end(template) 은 응답 헤더를 보내고, template 변수의 값을 응답 본문으로 전송하여 클라이언트에게 응답을 완료한다.


🖍 Node.js - 파일 읽기

var fs = require('fs');
fs.readFile('sample.txt', 'utf8', function(err, data){
  console.log(data);
});

이 코드는 Node.js에서 파일을 읽는 방법을 보여준다.
fs 모듈을 가져와서 readFile() 함수를 호출한다. readFile() 함수는 파일 이름, 인코딩 및 콜백 함수를 인수로 받는다. 콜백 함수는 파일 읽기 작업이 완료되면 호출되며 두 개의 인수인 에러와 데이터를 받는다. 오류가 없으면 data 인수는 파일의 내용을 포함하는 문자열이다.


4. 파일을 이용해 본문 구현

👩‍💻

var http = require('http');
var fs = require('fs');
var url = require('url');
 
var app = http.createServer(function(request,response){
    var _url = request.url;
    var queryData = url.parse(_url, true).query;
    var title = queryData.id;
    if(_url == '/'){
      title = 'Welcome';
    }
    if(_url == '/favicon.ico'){
      return response.writeHead(404);
    }
    response.writeHead(200);
    fs.readFile(`data/${queryData.id}`, 'utf8', function(err, description){
      var template = `
      <!doctype html>
      <html>
      <head>
        <title>WEB1 - ${title}</title>
        <meta charset="utf-8">
      </head>
      <body>
        <h1><a href="/">WEB</a></h1>
        <ul>
          <li><a href="/?id=HTML">HTML</a></li>
          <li><a href="/?id=CSS">CSS</a></li>
          <li><a href="/?id=JavaScript">JavaScript</a></li>
        </ul>
        <h2>${title}</h2>
        <p>${description}</p>
      </body>
      </html>
      `;
      response.end(template);
    })
 
 
});
app.listen(3000);

fs 모듈의 readFile 함수를 사용하여 파일 시스템에서 데이터 파일을 읽어온다. 데이터 파일의 경로는 data/${queryData.id} 로 지정된다. ${queryData.id} 는 URL의 'id' 쿼리 매개 변수의 값을 나타낸다. 파일은 utf8 인코딩으로 읽혀지며, 콜백 함수에서 읽어온 데이터를 description 변수에 저장한다.

template 변수에 있는 HTML 코드의 <p>${description}</p> 부분은 description 변수에 저장된 데이터를 출력하는 부분이다.


5. Not found 오류 구현

👩‍💻

var http = require('http');
var fs = require('fs');
var url = require('url');
 
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;
    var title = queryData.id;
 
    if(pathname === '/'){
      fs.readFile(`data/${queryData.id}`, 'utf8', function(err, description){
        var template = `
        <!doctype html>
        <html>
        <head>
          <title>WEB1 - ${title}</title>
          <meta charset="utf-8">
        </head>
        <body>
          <h1><a href="/">WEB</a></h1>
          <ul>
            <li><a href="/?id=HTML">HTML</a></li>
            <li><a href="/?id=CSS">CSS</a></li>
            <li><a href="/?id=JavaScript">JavaScript</a></li>
          </ul>
          <h2>${title}</h2>
          <p>${description}</p>
        </body>
        </html>
        `;
        response.writeHead(200);
        response.end(template);
      });
    } else {
      response.writeHead(404);
      response.end('Not found');
    }
 
 
 
});
app.listen(3000);

pathname 변수를 사용하여 요청된 URL의 경로 부분을 추출한다. url.parse(_url, true).pathname 을 통해 얻어진다.

그리고 if(pathname === '/') 는 경로가 / 인 경우에만 파일 읽기 및 응답을 처리하는 로직을 실행하고, 경로가 /가 아닌 경우에는 404 오류 응답을 반환한다.


6. 홈페이지 구현

👩‍💻

var http = require('http');
var fs = require('fs');
var url = require('url');
 
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.readFile(`data/${queryData.id}`, 'utf8', function(err, description){
          var title = 'Welcome';
          var description = 'Hello, Node.js';
          var template = `
          <!doctype html>
          <html>
          <head>
            <title>WEB1 - ${title}</title>
            <meta charset="utf-8">
          </head>
          <body>
            <h1><a href="/">WEB</a></h1>
            <ul>
              <li><a href="/?id=HTML">HTML</a></li>
              <li><a href="/?id=CSS">CSS</a></li>
              <li><a href="/?id=JavaScript">JavaScript</a></li>
            </ul>
            <h2>${title}</h2>
            <p>${description}</p>
          </body>
          </html>
          `;
          response.writeHead(200);
          response.end(template);
        });
      } else {
        fs.readFile(`data/${queryData.id}`, 'utf8', function(err, description){
          var title = queryData.id;
          var template = `
          <!doctype html>
          <html>
          <head>
            <title>WEB1 - ${title}</title>
            <meta charset="utf-8">
          </head>
          <body>
            <h1><a href="/">WEB</a></h1>
            <ul>
              <li><a href="/?id=HTML">HTML</a></li>
              <li><a href="/?id=CSS">CSS</a></li>
              <li><a href="/?id=JavaScript">JavaScript</a></li>
            </ul>
            <h2>${title}</h2>
            <p>${description}</p>
          </body>
          </html>
          `;
          response.writeHead(200);
          response.end(template);
        });
      }
    } else {
      response.writeHead(404);
      response.end('Not found');
    }
});
app.listen(3000);

pathname에 따른 분기처리 후, queryData.id 의 유무를 추가로 확인해 응답을 처리한다.

if (queryData.id === undefined)queryData.id 가 정의되지 않은 경우에 대한 처리이다. 즉, URL에 id 쿼리 매개 변수가 없는 경우를 의미한다. 이 경우에는 기본적인 환영 메세지를 표시하는 HTML 응답을 보낸다.


🖍 Node.js - 파일 목록 알아내기

var testFolder = './data';
var fs = require('fs');
 
fs.readdir(testFolder, function(error, filelist){
  console.log(filelist);
})

이 코드는 testFolder 폴더에 있는 모든 파일의 목록을 출력해준다.

  • var testFolder = './data'; 는 testFolder라는 이름의 폴더를 가리키는 문자열을 생성.
  • var fs = require('fs'); 는 fs 모듈을 가져옴.
  • fs.readdir(testFolder, function(error, filelist){...}는 fs 모듈의 readdir() 함수를 호출. 이 함수는 testFolder 폴더에 있는 모든 파일의 이름을 배열로 반환.

Node.js에서 파일 입출력 처리를 할 때에는 fs모듈을 사용한다. fs모듈에는 파일 읽기, 쓰기, 삭제등 파일관련 기능을 제공한다.


7. 글목록 출력하기

👩‍💻

var http = require('http');
var fs = require('fs');
var url = require('url');
 
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 = '<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>';
          var template = `
          <!doctype html>
          <html>
          <head>
            <title>WEB1 - ${title}</title>
            <meta charset="utf-8">
          </head>
          <body>
            <h1><a href="/">WEB</a></h1>
            ${list}
            <h2>${title}</h2>
            <p>${description}</p>
          </body>
          </html>
          `;
          response.writeHead(200);
          response.end(template);
        })
 
 
 
      } else {
        fs.readdir('./data', function(error, filelist){
          var title = 'Welcome';
          var description = 'Hello, Node.js';
          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>';
          fs.readFile(`data/${queryData.id}`, 'utf8', function(err, description){
            var title = queryData.id;
            var template = `
            <!doctype html>
            <html>
            <head>
              <title>WEB1 - ${title}</title>
              <meta charset="utf-8">
            </head>
            <body>
              <h1><a href="/">WEB</a></h1>
              ${list}
              <h2>${title}</h2>
              <p>${description}</p>
            </body>
            </html>
            `;
            response.writeHead(200);
            response.end(template);
          });
        });
      }
    } else {
      response.writeHead(404);
      response.end('Not found');
    }
 
 
 
});
app.listen(3000);

fs.readdir('./data', function(error, filelist){})./data 디렉토리에서 파일 목록을 가져오는 기능을 추가한다. 이를 통해 파일 목록을 반복하고, 각 파일에 대한 링크를 생성하여 페이지의 목차 부분에 표시할 수 있다.

list 변수는 파일 목록을 가지고 <ul> 태그를 생성한다. while 루프를 사용해 파일 목록을 반복하고, 각 파일에 대한 링크를 <li> 태그로 생성하여 list 변수에 추가한다.


8. App - 함수를 이용해서 정리 정돈하기

👩‍💻

var http = require('http');
var fs = require('fs');
var url = require('url');
 
function templateHTML(title, list, body){
  return `
  <!doctype html>
  <html>
  <head>
    <title>WEB1 - ${title}</title>
    <meta charset="utf-8">
  </head>
  <body>
    <h1><a href="/">WEB</a></h1>
    ${list}
    ${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}`);
          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}`);
            response.writeHead(200);
            response.end(template);
          });
        });
      }
    } else {
      response.writeHead(404);
      response.end('Not found');
    }
 
 
 
});
app.listen(3000);

코드의 가독성과 재사용성을 높이기 위해 templateHTML, templateList 함수를 생성하였다.

  • templateHTML 함수는 HTML 템플릿을 생성하는 역할을 한다. title, list, body 를 매개변수로 받아 템플릿에 적용해 완전한 HTML 문자열을 반환한다.
  • templateList 함수는 파일 목록을 기반으로 목차를 생성하는 역할을 한다. fileList를 매개변수로 받아 파일 목록을 반복하고 각 파일에 대한 링크를 생성해 <ul> 태그로 둘러싼 문자열을 반환한다.

이처럼 함수로 분리하여 중복 코드를 제거하고 코드의 가독성과 재사용성이 개선됐다.


9. 글생성 UI 만들기

👩‍💻

var http = require('http');
var fs = require('fs');
var url = require('url');
 
function templateHTML(title, list, body){
  return `
  <!doctype html>
  <html>
  <head>
    <title>WEB1 - ${title}</title>
    <meta charset="utf-8">
  </head>
  <body>
    <h1><a href="/">WEB</a></h1>
    ${list}
    <a href="/create">create</a>
    ${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}`);
          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}`);
            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="http://localhost:3000/process_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.writeHead(200);
        response.end(template);
      });
    } else {
      response.writeHead(404);
      response.end('Not found');
    }
 
 
 
});
app.listen(3000);

create 기능이 추가됐다. create 페이지를 생성하여 사용자가 제목과 설명을 입력할 수 있는 양식을 제공하고, 제출 시 해당 내용을 처리하는 기능이 구현됐다.

새로운 페이지 생성을 위해 /create 경로가 추가되었다. 접근 시 사용자가 제목과 설명을 입력할 수 있는 양식이 표시된다.

templateHTML 함수가 수정되어 새로운 페이지 생성 양식을 포함하도록 변경됐다. 새로운 양식은 titledescription 필드가 있는 <form> 태그로 구성되어 있으며, submit 버튼 클릭시 process_create 경로로 데이터가 전송된다.

해당 코드에서는 /process_create 경로는 아직 구현되어 있지 않으므로 아무런 동작이 수행되진 않는다.

app 서버 리스너 내에 /create 경로에 대한 조건문이 추가되었다. 이 조건문은 /create 경로에 대한 요청을 처리하며, 파일 목록과 함께 templateHTML 함수를 사용하여 새로운 페이지 생성 양식을 포함한 HTML 템플릿을 생성한다.

하여 이전 코드의 기능을 유지하면서 create 페이지를 추가하여 사용자가 새로운 페이지를 생성할 수 있는 기능을 제공한다.


10. 파일생성과 리다이렉션

👩‍💻

var http = require('http');
var fs = require('fs');
var url = require('url');
var qs = require('querystring');
 
function templateHTML(title, list, body){
  return `
  <!doctype html>
  <html>
  <head>
    <title>WEB1 - ${title}</title>
    <meta charset="utf-8">
  </head>
  <body>
    <h1><a href="/">WEB</a></h1>
    ${list}
    <a href="/create">create</a>
    ${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}`);
          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}`);
            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="http://localhost:3000/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 {
      response.writeHead(404);
      response.end('Not found');
    }
});
app.listen(3000);

create 기능을 완전히 구현하였다. 사용자가 제목과 설명을 입력하고 제출하면 해당 내용을 파일로 저장하는 기능이 추가됐다.

qu 모듈을 추가, 사용하여 POST 요청의 본문(body)데이터를 파싱한다. 이를 통해 사용자가 입력한 제목과 설명을 추출할 수 있다.

/create_process 경로에 대한 조건문이 추가되었다. 이 조건문은 POST 요청의 본문 데이터를 수신하고, 해당 데이터를 파싱하여 제목과 설명을 추출한다. 그 후, 추출한 데이터를 사용하여 새로운 파일을 생성하고, 생성된 파일로 리다이렉트 한다.

fs.writeFile 함수를 사용하여 추출한 제목을 파일 이름으로, 추출한 설명을 파일 내용으로 하는 파일을 생성한다.

이렇게 변경된 코드는 create 페이지에서 제목과 설명을 입력받아 파일로 저장하는 기능을 완성한다.


11. 수정 링크 생성

👩‍💻

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="http://localhost:3000/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 {
      response.writeHead(404);
      response.end('Not found');
    }
});
app.listen(3000);

update 기능을 추가하였다. 사용자는 특정페이지에서 update 링크를 클릭해 해당 페이지의 제목과 내용을 수정할 수 있다.

templateHTML 함수에 control 매개변수를 추가해 페이지 상단에 표시되는 추가 컨트롤 요소를 나타냈다. 이것으로 create링크와 update링크를 표시하는 데 사용된다.

/경로에서 특정페이지를 표시할 때, 해당 페이지의 제목과 내용 아래에 update 링크가 추가되었다. 이 링크는 해당 페이지의 내용을 수정하는 페이지로 이동하는 역할을 한다.

/update 경로를 추가하여 특정 페이지의 제목을 수정할 수 있는 페이지로 이동한다. 수정된 제목을 받아와 해당 페이지의 내용을 수정할 수 있게된다.

fs.writeFile함수 호출 시 Location 헤더의 URL이 변경된다. 그리하여/?id=${title} 형식으로 리다이렉트되어 해당 페이지의 내용이 수정된 것을 표시한다.


12. 수정할 정보 전송

👩‍💻

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 {
      response.writeHead(404);
      response.end('Not found');
    }
});
app.listen(3000);

update 경로에 대한 조건문이 추가되었다. 해당 경로에서는 기존 페이지의 내용을 수정할 수 있는 양식이 표시된다. 이 때, 양식의 각 입력 필드에는 기존 제목과 내용이 미리 입력되어 있다.

update 양식을 제출하면 /update_process 경로로 POST 요청이 전송된다. 이 경로에서는 제출된 내용을 받아와 해당 페이지의 제목과 내용을 수정하고, 수정된 내용을 파일에 저장한다.

input 요소의 type="hidden" 를 추가하여 수정할 페이지의 제목을 식별한다. 이 input 요소는 사용자에게 표시되지 않고 양식을 제출할 때 전송된다.

이로인해 update 기능을 추가하여 사용자가 페이지의 내용을 수정할 수 있도록 한다.


13. 수정된 내용 저장

👩‍💻

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

fs.rename 함수를 추가해 수정된 페이지의 파일명을 변경한다. 이 함수는 기존 파일명 id를 새 파일명 title 로 변경한다.


14. 글 삭제

👩‍💻

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>
                <form action="delete_process" method="post">
                  <input type="hidden" name="id" value="${title}">
                  <input type="submit" value="delete">
                </form>`
            );
            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 if(pathname === '/delete_process'){
      var body = '';
      request.on('data', function(data){
          body = body + data;
      });
      request.on('end', function(){
          var post = qs.parse(body);
          var id = post.id;
          fs.unlink(`data/${id}`, function(error){
            response.writeHead(302, {Location: `/`});
            response.end();
          })
      });
    } else {
      response.writeHead(404);
      response.end('Not found');
    }
});
app.listen(3000);

delete 기능을 추가하였다.

/delete_process 경로를 추가하여 삭제 작업을 처리할 수 있다. 해당 경로로 POST 요청이 전송되면 해당 파일을 삭제하는 작업이 수행된다.

각 페이지에 삭제버튼이 추가됐다. 사용자는 삭제 버튼을 클릭하여 해당 페이지를 삭제할 수 있다. 삭제 버튼은 /delete_process 경로로 제출된다.

fs.unlink 함수를 추가하여 파일을 삭제한다. 이 함수는 파일을 제거한다.

수정된 페이지에는 create, update, delete 버튼이 함께 표시된다. 사용자는 수정 버튼을 통해 페이지를 수정하고, 삭제 버튼을 통해 페이지를 삭제할 수 있다.


15. 객체를 이용해 템플릿 기능 정리정돈

👩‍💻

var http = require('http');
var fs = require('fs');
var url = require('url');
var qs = require('querystring');
 
var template = {
  HTML:function(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>
    `;
  },list:function(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 = template.list(filelist);
          var html = template.HTML(title, list,
            `<h2>${title}</h2>${description}`,
            `<a href="/create">create</a>`
          );
          response.writeHead(200);
          response.end(html);
        });
      } else {
        fs.readdir('./data', function(error, filelist){
          fs.readFile(`data/${queryData.id}`, 'utf8', function(err, description){
            var title = queryData.id;
            var list = template.list(filelist);
            var html = template.HTML(title, list,
              `<h2>${title}</h2>${description}`,
              ` <a href="/create">create</a>
                <a href="/update?id=${title}">update</a>
                <form action="delete_process" method="post">
                  <input type="hidden" name="id" value="${title}">
                  <input type="submit" value="delete">
                </form>`
            );
            response.writeHead(200);
            response.end(html);
          });
        });
      }
    } else if(pathname === '/create'){
      fs.readdir('./data', function(error, filelist){
        var title = 'WEB - create';
        var list = template.list(filelist);
        var html = template.HTML(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(html);
      });
    } 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 = template.list(filelist);
          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?id=${title}">update</a>`
          );
          response.writeHead(200);
          response.end(html);
        });
      });
    } 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 if(pathname === '/delete_process'){
      var body = '';
      request.on('data', function(data){
          body = body + data;
      });
      request.on('end', function(){
          var post = qs.parse(body);
          var id = post.id;
          fs.unlink(`data/${id}`, function(error){
            response.writeHead(302, {Location: `/`});
            response.end();
          })
      });
    } else {
      response.writeHead(404);
      response.end('Not found');
    }
});
app.listen(3000);

template 객체를 사용하여 기존의 templateHTML, templateList 함수를 HTML, list 라는 두 개의 메서드로 변경했다. 이 메서드는 HTML과 파일목록을 생성하는 역할을 한다.

최종적으로 이 코드는 CRUD 기능을 제공하며, 요청된 경로에 따라 적절한 응답을 생성한다.

profile
필기하고 기록하고

0개의 댓글