본문으로 바로가기

express와 같은 프레임워크가 아닌 순수한 node로 웹 서버를 만들어보자.

 

딱히 실용성이 있어서 만들기보다는 node에 대한 지식을 늘리기 위함이며 여기서 구현한 쿠키, 세션 등은 실무에서 사용하는 것이 아니라 어떠한 원리인지 설명하기 위해 간략하게 작성한 것이다. 실무에서는 다른 사람이 구현한 모듈을 사용하는 것이 대부분이다.

 

https://stackoverflow.com/questions/41786986/vanilla-node-vs-express

 

Vanilla Node vs Express

I'm wondering if some of you veterans could provide some guidance to some of us noobs. Is there any advantage to writing vanilla Node over using Express? More specifically, any particular scenario

stackoverflow.com

 

진행하기에 앞서 http에 대한 간단한 지식과 node 내장 모듈에 대해서 알고 있어야 한다.


간단히 http 내장 모듈을 이용하여 간단히 서버를 구동해보자.

import http from "http";

const server = http
  .createServer((req, res) => {
    console.log("서버 실행");
    res.write("<h1>Hello Node</h1>");
    res.write("<h2>It's Vanilla Node</h2>");
    res.end("<p>Hello Server</p>"); // 마지막 wrtie는 end로 끝냄.
  })

server.listen(8080, () => console.log("http://localhost:8080"));
server.on("error", err => console.warn(err));

http://localhost:8080/로 접속하면 작성한 html이 보인다.

 

localhost:8080 접속

 

 

이제 하나씩 개선해나가보자.

 

html 파일 불러오기

 

html을 res.write와 res.end로 모두 처리하는 것을 효율적이지 못하다. html 파일을 불러오는 방식을 이용하자.

fs 내장 모듈을 이용하여 파일을 불러오자. 이를 위해 동일 경로에 index.html을 생성해두었다.

여기서 의문점은. data.toString()을 사용하지 않았다는 것인데 버퍼 형태로 제공되더라도 브라우저가 해석하기 때문에 괜찮다.

import http from "http";
import fs from "fs";

const server = http.createServer((req, res) => {
  console.log("서버 실행");
  fs.readFile("./index.html", (err, data) => {
    if (err) {
      console.warn(err);
    }
    res.end(data);
  });
});

server.listen(8080, () => console.log("✔success : http://localhost:8080"));
server.on("error", err => console.warn(err));

 

쿠키와 세션

클라이언트 측에서 req을 날리면 서버는 쿠키와 함께 res를 날린다. 이후 해당 클라이언트가 쿠키와 함께 req를 날리면 쿠키 정보를 확인하여 서버가 응답한다. 로그인을 생각해보면 이해할 수 있다.

 

html에서 form을 작성했을 때 res, req header와 application 탭의 cookie에서 내용을 확인할 수 있다.

이 쿠키를 이용하여 url이 /login으로 접속했을 때 다른 화면을 출력하도록 라우터 분기도 설정해보았다.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>쿠키&세션 이해하기</title>
  </head>
  <body>
    <form action="/login">
      <input id="name" name="name" placeholder="이름을 입력하세요" />
      <button id="login">로그인</button>
    </form>
  </body>
</html>
import http from "http";
import fs from "fs";
import url from "url";
import qs from "querystring";

//쿠키를 사용 가능한 객체로 파싱하는 함수
//보통 npm에서 cookie-parser를 설치해서 해결한다.
const parseCookies = (cookie = "") =>
  cookie
    .split(";")
    .map(v => v.split("="))
    .reduce((acc, [k, v]) => {
      acc[k.trim()] = decodeURIComponent(v);
      return acc;
    }, {});

const server = http.createServer((req, res) => {
  const cookies = parseCookies(req.headers.cookie);
  if (req.url.startsWith("/login")) {
    const { query } = url.parse(req.url); //req.url에는 /login?name=입력값
    const { name } = qs.parse(query); //query에는 name=입력값
    res.writeHead(200, {
      "Set-Cookie": `name=${encodeURIComponent(name)}` //encode..를 해야 한글이 안 깨짐
    });
    res.end(`<h1>Hello ${name}</h1>`);
  } else {
    fs.readFile("./index.html", (err, data) => {
      if (err) {
        console.warn(err);
      }
      res.end(data);
    });
  }
});

server.listen(8080, () => console.log("✔success : http://localhost:8080"));
server.on("error", err => console.warn(err));

 

개발자 도구에서 Cookie를 확인할 수 있다. Network 탭의 request header 속 Cookie 부분과 application 탭의 cookies에서 확인할 수 있다.

 

tip) 상태 코드 200이 아니라 302를 통해 Redirection을 할 수 있다. 다음 코드를 입력할 경우 /로 redirect 하되 res header에서 쿠키를 설정한다.

res.writeHead(302, {
      Location: "/",
      "Set-Cookie": `name=${encodeURIComponent(name)}` //encode..를 해야 한글이 안 깨짐
    });

 

 

그런데 쿠키를 이렇게 사용하면 개발자 도구를 열어보는 것만으로도 사용자의 쿠키 정보를 쉽게 알 수 있어 보안상에 문제점이 생긴다. 세션을 이용해 서버의 메모리에 정보를 저장해보자.

import http from "http";
import fs from "fs";
import url from "url";
import qs from "querystring";

// parseCookies 함수 생략

const session = {}; // 세션 함수

const server = http.createServer((req, res) => {
  const cookies = parseCookies(req.headers.cookie);
  if (req.url.startsWith("/login")) {
    const { query } = url.parse(req.url);
    const { name } = qs.parse(query);
    const randomInt = +new Date();
    session[randomInt] = {
      name
    };
    res.writeHead(302, {
      Location: "/",
      "Set-Cookie": `name=${randomInt}`
    });
    res.end(`<h1>Hello ${name}</h1>`);
  } else {
    fs.readFile("./index.html", (err, data) => {
      if (err) {
        console.warn(err);
      }
      res.end(data);
    });
  }
});

server.listen(8080, () => console.log("✔success : http://localhost:8080"));
server.on("error", err => console.warn(err));

 

쿠키와 세션을 직접 구현하려고 하지 말자. 어차피 다른 사람이 작성한 모듈을 이용하는 게 대부분이니까. vanilla node를 연습했다고 생각하자.


darren, dev blog
블로그 이미지 DarrenKwonDev 님의 블로그
VISITOR 오늘 / 전체