[Node.js 훑어보기] #4 웹 서버 만들어보기!!

mechaniccoder·2020년 7월 23일
0

Node.js 알아가기

목록 보기
4/7
post-thumbnail

http모듈로 웹 서버 만들기!


자! 모듈에 대한 공부는 어느정도 했으니 node.js를 사용해서 웹 서버를 만들어보죠. 웹 서버를 만들기 위해서 http모듈을 사용할 것 입니다.

const http = require("http");

const server = http.createServer((req, res) => {
  res.write("<h1>hi node.js!</h1>"); // 클라이언트로 데이터를 보냅니다.
  res.end("<p>hello my first node.js server!</p>"); // 클라이언트로 데이터를 보내고 응답을 종료합니다.
});

server.listen(8080);
server.on("listening", () => {
  console.log("8080포트 서버 대기 중!");
});
server.on("error", (err) => {
  console.error(err);
});
  • end 메서드를 사용할 때 인자가 있으면 그 인자를 마지막 데이터로 보내고 응답을 종료합니다.
  • on 메서드로 각각 listeningerror 이벤트에 해당되는 콜백 함수를 등록할 수 있습니다.

html 파일을 클라이언트로 보낼 수도 있습니다. 특히 앞 장에서 배운 버퍼를 보낼 수도 있어요.

const http = require("http");
const fs = require("fs");

const server = http.createServer((req, res) => {
  fs.readFile("./server.html", (err, data) => {
    if (err) throw err;
    res.end(data); // toString()으로 변환하지 않고 바로 버퍼를 보냈죠?
  });
});

server.listen(8080);
server.on("listening", () => {
  console.log("8080포트 서버 대기 중이다. 오버!");
});
server.on("error", (err) => {
  console.error(err);
});

클라이언트에 따른 서버 응답 조작하기


위에서 만들어본 서버는 모든 요청에 대해서 항상 같은 응답을 반환합니다. 즉, 클라이언트를 구별하지 않는다는 말이죠. 그럼 구별하려면 어떻게 해야 할까요? 여기서 그 유명한 쿠키와 세션이 등장합니다.

쿠키와 세션(cookie and session)

클라이언트를 기억하기 위해서 서버는 첫 요청에 대해 응답할 때 쿠키라는 것을 보내줍니다. 브라우저는 쿠키를 저장하고 서버에 요청을 보낼 때 이 쿠키를 같이 보내죠. 즉, 내가 누구에요! 라고 계속 말해주는 것입니다. 따라서 우리는 클라이언트로 보내는 쿠키를 구현하기만 하면됩니다. 이후엔 브라우저가 자동으로 쿠키를 보낼거거든요.

쿠키는 요청과 응답의 헤더에 저장됩니다. 요청과 응답 각각은 헤더(header)와 본문(body)으로 되어있어요. 자 그럼 로그인 기능을 맛보기로 만들면서 브라우저로 쿠키를 보내봅시다.

const http = require("http");
const fs = require("fs");
const url = require("url");
const qs = require("querystring");

const parseCookies = (cookies = "") =>
  cookies
    .split(";")
    .map((v) => v.split("="))
    .map(([k, ...vs]) => [k, vs.join("=")])
    .reduce((acc, [k, v]) => {
      acc[k.trim()] = decodeURIComponent(v);
      return acc;
    }, {});

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 expires = new Date();
      expires.setMinutes(expires.getMinutes() + 5);
      res.writeHead(302, {
        Location: "/",
        "Set-Cookie": `name=${encodeURIComponent(
          name
        )}; Expire=${expires.toGMTString()}; HttpOnly; Path=/`,
      });
      res.end();
    } else if (cookies.name) {
      res.writeHead(200, {"Content-Type": "text/html; charset=utf-8"});
      res.end(`${cookies.name}님 안녕하세요.`);
    } else {
      fs.readFile("./server.html", (err, data) => {
        if (err) throw err;
        res.end(data);
      });
    }
  })
  .listen(8081, () => {
    console.log("8081포트에서 서버 대기중입니다.");
  });

쿠키를 설정 시에 다양한 옵션을 줄 수 있습니다.

  • 쿠키명=쿠키값 : 기본적인 쿠키를 설정합니다.
  • Expires=날짜 : 만료기한을 설정합니다. 이 기간이 지나게 되면 쿠키가 삭제됩니다. 기본값은 클라이언트가 종료될 때까지 유지됩니다.
  • Max-age=초 : Expires랑 비슷한데 날짜가 아닌 초를 입력합니다. 마찬가지로 기간이 지나면 쿠키가 삭제되겠죠. Expires보다 우선적으로 적용됩니다.
  • Domain=도메인명 : 쿠키가 전송될 도메인을 정합니다. 기본값은 현재 위치한 도메인입니다.
  • Path=URL : 쿠키가 전송될 URL을 정할 수 있습니다. 기본값은 '/' 이며 이 경우 모든 URL에 쿠키를 전송합니다.
  • Secure : HTTPS일 경우에만 쿠키가 전송됩니다.
  • HttpOnly: 자바스크립트에서 쿠키에 접근할 수 없습니다. 쿠키 조작을 방지하죠.

그런데 만약 위와 같이 코드를 작성해서 브라우저 쿠키를 보내게 되면 사용자의 개인정보가 누출될 수 있는 위험이 있겠죠. 따라서 서버단에서 정보를 처리해줘야합니다. 즉, 세션 처리하는 로직을 보죠.

const session = {};

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 expires = new Date();
      expires.setMinutes(expires.getMinutes() + 5);
      const randomInt = new Date();
      session[randomInt] = {
        name,
        expires,
      };
      res.writeHead(302, {
        Location: "/",
        "Set-Cookie": `session=${randomInt}; Expires=${expires.toISOString()}; HttpOnly; Path=/`,
      });
      res.end();
    } else if (
      cookies.session &&
      session[cookies.session].expires > new Date()
    ) {
      res.writeHead(200, {"Content-Type": "text/html; charset=utf-8"});
      res.end(`${session[cookies.session].name}님 반갑습니다.`);
    } else {
      fs.readFile("./server.html", (err, data) => {
        if (err) throw err;
        res.end(data);
      });
    }
  })
  .listen(8081, () => {
    console.log("8081포트 작동 중");
  });

이 방법을 사용하면 실제 정보를 브라우저에 저장하는 것이 아니라 설정한 randomInt를 통해서만 소통하게 됩니다. 하지만 실제로는 세션을 변수에 저장하지 않습니다. 메모리에 초기화되거나 부족하면 세션을 사용할 수 없기 때문이죠. 절대로 이렇게 사용하지마세요. 그냥 쿠키와 세션의 개념을 잡기 위해 정리해본 겁니다.

References


  • 조현영『Node.js 교과서』, (주)도서출판 길벗(2019년 2월 2일), p.103~ 110
profile
세계 최고 수준을 향해 달려가는 개발자입니다.

0개의 댓글