nodejs로 서버를 만들 때는 express모듈을 많이 사용하지만 기본적으로 http모듈을 통해서도 서버를 만들 수 있습니다. http모듈을 통해 http 서버를 만들고 라우터를 설정하는 방법에 대해서 정리하는 글입니다.


http서버 만들기

server.js

const http = require("http");
const server = http.createServer((req, res) => {});
server.listen(8080, () => console.log("8080번 포트에서 서버 대기 중"));

http모듈은 노드애 기본으로 내장되어있기 때문에 아래처럼 사용할 수 있습니다.

createServer

http 모듈의 메서드인 createServer 로 서버를 만들 수 있습니다. createServer는 요청(req), 응답(res)를 인자로 받는 함수를 인자로 받습니다. 해당 함수에서 요청과 응답에 대한 처리로직을 작성합니다.

listen

이렇게만 작성하여도 서버가 만들어집니다. 하지만 서버는 특정 포트를 열어놓고 요청을 기다리는 동작이 필요합니다.

**실행 **

노드 명령어를 통해 서버를 실행시킬 수 있습니다.

node server.js

응답으로 파일 읽어서 보내기

노드의 기본 내장 모듈인 fs을 사용해서 사용자가 해당 서버 URL에 접속하면 html파일을 응답으로 주려고 합니다.

server.js와 같은 경로에 server.html을 만들어줍니다.

server.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>server</title>
  </head>
  <body>
    <h1>server</h1>
  </body>
</html>

server.js

const http = require("http");
const fs = require("fs");
const server = http.createServer((req, res) => {
  fs.readFile("./server.html", function(err, data) {
    if (err) {
      throw err;
    }
    res.end(data);
  });
});

server.listen(8080, () => console.log("8080번 포트에서 서버 대기 중"));

결과 화면

image

fs모듈을 통해 사용자가 서버의 특정 URL에 접속하였을 때 즉, 서버에게 요청을 하였을 때 html 파일로 응답하는 방법을 알아봤습니다.

규모가 커지더라도 사용자가 서버의URL 로 접속하고 서버는 사용자가 접속한 URL에 맞는 응답을 해주는 흐름은 변하지 않습니다.

쿠키 설정, req.url

위에서는 URL을 접속하면 서버에서 파일을 응답해주는 부분이었는데, 이번에는 서버와 브라우저가 쿠기를 통해 데이터를 주고받는 방법을 알아보려합니다.

응답에 쿠키 담아서 보내기

const http = require("http");
const fs = require("fs");
const server = http.createServer((req, res) => {
  res.writeHead(200, {
    "Set-Cookie": "name=mansub"
  });
  fs.readFile("./server.html", function(err, data) {
    if (err) {
      throw err;
    }
    res.end(data);
  });
});

server.listen(8080, () => console.log("8080번 포트에서 서버 대기 중"));

쿠키에 추가된 것을 확인할 수 있습니다.

image

네트워크 탭을 통해 Set Cookie를 response Header에 담아서 보낸 것도 확인할 수 있습니다.

image

**req에 담겨온 cookie parse하기 **

parseCookies함수를 통해 req.headers.cookie를 파싱합니다.

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

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

const server = http.createServer((req, res) => {
  console.log(req.url, parseCookies(req.headers.cookie));
  res.writeHead(200, {
    "Set-Cookie": "name=mansub"
  });
  fs.readFile("./server.html", function(err, data) {
    if (err) {
      throw err;
    }
    res.end(data);
  });
});

server.listen(8080, () => console.log("8080번 포트에서 서버 대기 중"));

로그인 하면 쿠키 저장하고 저장된 쿠키있으면 보여주기

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

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

const server = http.createServer((req, res) => {
  const cookie = parseCookies(req.headers.cookie);
  if (req.url.startsWith("/login")) {
    const { query } = url.parse(req.url);
    const { name } = querystring.parse(query);
    res.writeHead(302, { Location: "/", "Set-Cookie": `name=${encodeURIComponent(name)};` });
    res.end();
  } else if (cookie.name) {
    res.writeHead(200, {
      "Content-Type": "text/html; charset=utf-8"
    });
    res.end(`${cookie.name}님 환영합니다.`);
  } else if (req.url === "/") {
    fs.readFile("./form.html", function(err, data) {
      if (err) {
        throw err;
      }
      res.end(data);
    });
  }
});

server.listen(8080, () => console.log("8080번 포트에서 서버 대기 중"));

메모리 세선 구현해보기

아직 DB를 연결하지 않았기 때문에 session라는 빈 배열을 통해 메모리 세션을 구현해보겠습니다.

if (req.url.startsWith("/login")) {
    const { query } = url.parse(req.url);
    const { name } = querystring.parse(query);
    const randomInt = +new Date();
    session[randomInt] = {
      name
    };
    res.writeHead(302, { Location: "/", "Set-Cookie": `session=${randomInt};` });
    res.end();
  }

form을 통해 사용자의 이름을 입력 받으면 /login경로로 이동하게 되고, 현재 날짜를 통해 랜덤한 숫자를 만들고 세션의 랜덤숫자 인덱스에 유저의 정보를 저장하게 됩니다.

const server = http.createServer((req, res) => {
  const cookie = parseCookies(req.headers.cookie);
  if (req.url.startsWith("/login")) {
    const { query } = url.parse(req.url);
    const { name } = querystring.parse(query);
    const randomInt = +new Date();
    session[randomInt] = {
      name
    };
    res.writeHead(302, { Location: "/", "Set-Cookie": `session=${randomInt};` });
    res.end();
  } else if (cookie.session) {
    res.writeHead(200, {
      "Content-Type": "text/html; charset=utf-8"
    });
    res.end(`${session[cookie.session].name}님 환영합니다.`);
  } else if (req.url === "/") {
    fs.readFile("./form.html", function(err, data) {
      if (err) {
        throw err;
      }
      res.end(data);
    });
  }
});

그렇다면 위와 같이 쿠키의 session 값이 존재할 경우 해당 세션 인덱스에 존재하는 유저 정보를 응답으로 주면 브라우저에서는 의미없는 앤덤 숫자인 세션만 공개되고, 실제 중요한 정보는 서버에 저장해놓을 수 있는 것입니다.

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

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

const session = {};
const server = http.createServer((req, res) => {
  const cookie = parseCookies(req.headers.cookie);
  if (req.url.startsWith("/login")) {
    const { query } = url.parse(req.url);
    const { name } = querystring.parse(query);
    const randomInt = +new Date();
    session[randomInt] = {
      name
    };
    res.writeHead(302, { Location: "/", "Set-Cookie": `session=${randomInt};` });
    res.end();
  } else if (cookie.session) {
    res.writeHead(200, {
      "Content-Type": "text/html; charset=utf-8"
    });
    res.end(`${session[cookie.session].name}님 환영합니다.`);
  } else if (req.url === "/") {
    fs.readFile("./form.html", function(err, data) {
      if (err) {
        throw err;
      }
      res.end(data);
    });
  }
});

server.listen(8080, () => console.log("8080번 포트에서 서버 대기 중"));