Web 공부/Node JS

Node JS

sumiin 2022. 3. 17. 19:51
반응형
SMALL

Node js

URL

  • http://opentutorials.org:3000/main?id=HTML&page=12
  • http = protocol : 웹브라우저와 웹서버가 데이터를 주고받기 위해 만든 통신규칙
  • opentutorials.org= host(domain) : 인터넷에 접속되어 있는 각각의 컴퓨터(특정한 인터넷에 연결되어있는 컴퓨터를 가리키는 주소)
  • 3000=port : 접속할 때, 3000번 포트에 연결되어 있는 서버와 통신하게 됨(port 기본 값=80)
  • main =path : 컴퓨터 안에 있는 어떤 디렉토리에 어떤 파일인지 가리킴
  • id=HTML&page=12=query string : 웹서버에게 보내고 싶은 데이터 전달
  • 쿼리스트링의 시작은 ?
  • 값과 값은 & 로 연결
  • 값의 이름과 값은 = 로 구분

Template Literal

  • var (변수이름)=(HTML 코드) 를 통해 HTML styling 가능
  • ${ } : template내에 변수 사용

동기 vs 비동기

  • 동기적: 순차적으로 해결
  • 비동기적: 병렬적으로 여러가지 동시 해결

package manager

  • 패키지 매니저(Package manager)는 패키지를 다루는 작업을 편리하고 안전하게 수행하기 위해 사용되는 툴- pm2 사용
  • pm2 start main.js --watch

    • 이전에는 main.js를 수정하면 ctrl+s 후, cmd 창에서 ctrl+c를 눌러야 수정 내용이 반영됐었지만, 이 명령어 실행 후, 웹 서버에서 f5만 누르면 바로 반영됨
  • pm2 log

    • cmd에 문제점 바로 보여줌

Form

(문제 : readdir를 통해 data directory에 접근할 수 있는 것은 자기 자신 뿐이기 떄문에 컨텐츠의 생성은 소유자밖에 못함 )

  • Form : 사용자가 서버 쪽으로 데이터를 전송하기 위한 방식
    • 누구나 웹을 통해 데이터를 전송하면 사용자가 컨텐츠를 생성하고 삭제할 수 있게 함
<form action="http://localhost:3000/process_create" method="post">//사용자가 입력한 정보를 action에 입력한 서버로 전송
    <p><input type="text" name="title"></p> //글씨를 입력할 수 있음 
    <p>//본문에 여러줄 입력 가능한 태그
        <textarea name="description"></textarea>
    </P>
    <p><input type="submit"></p> //사용자가 입력을 끝낸 후, 전송하는 버튼 
</form>
//입력한 각각의 값들이 이름이 있어야 서버 쪽에서 받았을 때 의미가 있기 때문에 name으로 정의해줘야함 
서버에서 데이터를 가져올 때에는 ?를 이용하는  쿼리스트링 형태로 사용 (method="get",default 값이기 때문에 생략 가능 )
서버의 데이터를 수정하는 행위를 할 때에는 method="post" 라는 형식을 붙여줘서 user들이 submit해서 들어온 경우에는 서버주소에 쿼리스트링이 보이지 않도록 해줌 
  • form이라는 태그는 form안에 사용자가 입력한 각각의 정보를 submit버튼을 눌렀을 때, action속성이 가리키는 서버로 쿼리스트링의 형태로 데이터를 전송하는 기능

객체 Vs 배열

  • 공통점 : 정보를 정리정돈하는 도구
  • 배열: 순서에 따라서 정리를 하고 숫자로 구분을 함 (literal [ ])
  • 객체: 순서가 없음, 숫자가 아닌 각각의 고유한 이름으로 구분 가능 (literal { })
//array 반복문 호출
var members=['egoing','k8805','hoya'];
var i=0;
while(i<members.length){
    console.log(members[i]);
    i+=1;
}


//object 반복문 호출
var roles={
    'programmer':'egoing',
    'designer':'k8805',
    'manager':'hoya'}

for(var name in roles){
    console.log('object =>',name,'value =>',roles.name);
}

객체지향 프로그래밍

  • js에서 함수는 처리방법들을 담는 구문이면서 함수 자체가 값이 될 수 있다.
  • 객체는 값을 담는 그릇처럼 사용
  • 함수가 객체 안에서 사용될 때, 함수가 자신이 속한 객체를 참조할 수 있는 경우 this라는 키워드 사용
  • 코드의 복잡성을 줄일 수 있음

Module

  • 객체를 정리정돈할 수 있는 가장 큰 도구

<mpart.js>:module 파일

var M={
    v:'v',
    f:function(){
        console.log(this.v);
    }
}

module.exports=M;
//M의 객체를 외부에서 사용할 수 있도록 export 하겠다는 뜻 

<muse.js> :module 사용할 파일

var part=require('./mpart.js');
//mpart.js의 모듈을 part라는 변수에다 담음

part.f();//mpart.js의 M객체에서 f라는 함수를 사용할 때

API (Application Programming Interface)

  • Application을 Programming하기 위해 제공되는 Interface(언어가 가진 여러가지 기능, 장치들)
  • 그 언어가 가지고 있는 조작 장치가 궁금하다면 API를 검색해야함

<main.js>: 전체 코드

var http = require('http');
var fs = require('fs');
var url=require('url');//url이라는 모듈 사용한다는 것
var qs=require('querystring');
var template=require('./lib/template.js');//tenplate.js의 module사용
var path=require('path');
var sanitizeHtml=require('sanitize-html');//웹을 변경시킬 수 있는 예민한 태그들을 text로 쓰면 제거해버리는 효과 

var app = http.createServer(function(request,response){

  /*
  createServer: 웹서버를 만들고 웹서버에서 요청이 들어올때마다 첫번째 인자에 해당되는 함수를 호출
  웹브라우저 들어올때마다 createServer의 callback함수를 nodejs가 호출 `function(request,response){}`
  request: 요청할 때 웹브라우저가 user에게 보낸 정보들 담겨 있음 
  response: 응답할 때 user가 웹브라우저에게 전송할 정보들 담겨 있음 
  */
  var _url = request.url;
  var queryData=url.parse(_url,true).query;
  var pathname=url.parse(_url,true).pathname;//어떤 경로로 들어왔는지 확인
  if(pathname==='/'){//route일 때
    if(queryData.id===undefined){//id 없는 home 말하는 것
      fs.readdir('./data',function(error,filelist){//data 폴더에 있는 파일들을 읽어 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);//200이라는 숫자를 서버가 브라우저에게 주면 파일을 성공적으로 전송했다는 뜻
        response.end(html);//웹에 template출력

      });

    } else{    
      fs.readdir('./data',function(error,filelist){//data 폴더에 있는 파일들 이름을 filelist라는 배열로 만듦
        var filteredId=path.parse(queryData.id).base; //정보보안을 위해 데이터중 base만 전달
        fs.readFile(`data/${filteredId}.txt`, 'utf8',
        function(err,description){
          var list=template.List(filelist);
          var title=queryData.id;
          var sanitizedTitle=sanitizeHtml(title);
          var sanitizedDescription=sanitizeHtml(description);//태그들을 못쓰도록 살균, allowedTags안에 들어있는 태그들은 사용 가능 
          var html=template.HTML(sanitizedTitle,list,
            `<h2>${sanitizedTitle}</h2> ${sanitizedDescription}`,
            `<a href="/create">create</a>
            <a href="/update?id=${sanitizedTitle}">update</a>
            <form action="delete_process" method="post">
              <input type="hidden" name="id" value="${sanitizedTitle}">
              <input type="submit" value="delete">
            </form>`);
          response.writeHead(200);
          response.end(html);
        });
      });
      }

      /*
      웹주소에서 id값을 바꾸면 ${title}라고 한 부분, 전체 바뀜
      <a href="/?id=CSS"> :href 부분에 id값을 쓰면 그 태그 눌렀을 때,id 값이 바껴서 웹주소 id부분과 title 모두 바뀜
      fs.readFile에서 변수 description으로 받았기 때문에 ${}시 해당되는 부분의 본문 출력 
      */

  } else if(pathname==='/create'){//create 눌렀을 때
    fs.readdir('./data',function(error,filelist){
      var title='Web - create';
      var list=template.List(filelist);
      var html=template.HTML(title,list,`
      <h2>${title}</h2>
      <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>
      `,'');//form 을 body에 배치
      response.writeHead(200);
      response.end(html);
    });
  } else if(pathname==='/create_process'){//create 창에서 submit 버튼 누른 경우
    var body='';
    request.on('data',function(data){
      //웹브라우저가 post방식으로 전송되는 데이터가 많은 경우를 대비해 request.on 사용
      //특정한 양을 수신할 때마다 서버는 콜백함수인 function(data)를 호출해 data라는 인자를 통해 수신한 정보를 주가로 약속
      body=body+data;
    });

    request.on('end',function(){
      //더이상 들어올 데이터가 없으면 이 end 뒤의 callback 함수가 실행되도록 약속
      var post=qs.parse(body); //post데이터에 지금까지 입력한 data들 들어있는 body를 저장해서 객체화 시킴
      var title=post.title;
      var description=post.description;
      fs.writeFile(`data/${title}.txt`,description,'utf8',function(err){
        console.log(description);
        response.writeHead(302,{Location:`/?id=${title}`}); //Location으로 redirecrion(파일이 data에 저장되고 바로 서버로 이동)
        response.end();
      });   
    });
  }else if(pathname==='/update'){
    fs.readdir('./data',function(error,filelist){
      var filteredId=path.parse(queryData.id).base;
      fs.readFile(`data/${filteredId}.txt`, '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>`);
        /*
        html의 input 태그는 value라는 속성에 props 넣어주면 기본값으로 그 props가 들어가게됨
        name="id"는 update한 내용을 기존title에 보내기 위해 기존 title과 update된 title을 구분시키려고 만듦(user에게 보일 필요 없으니 type=hidden)
        */
        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 title=post.title;
      var id=post.id;
      var description=post.description;
      fs.rename(`data/${id}.txt`,`data/${title}.txt`,function(error){
        fs.writeFile(`data/${title}.txt`,description,'utf8',function(err){
          response.writeHead(302,{Location:`/?id=${title}`}); //Location으로 redirecrion(파일이 data에 저장되고 바로 서버로 이동)
          response.end();
      });

      })
      console.log(post);

    });

  } 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;
      var filteredId=path.parse(id).base;
      fs.unlink(`data/${filteredId}.txt`,function(error){
        response.writeHead(302,{Location:`/`});//redirection home으로 감
          response.end();
      })
    });

  } else{//path가 없는 경로로 접속했다면
    response.writeHead(404);//파일을 찾을 수 없는 경우
    response.end('Not found');
  }



});
app.listen(3000);//요청에 대해서 응답할 수 있도록 http 서버를 구동시킴 
반응형
LIST