코드코코

210914 [4장] 4.3 쿠키와 세션 이해하기 본문

기록/node.js 교과서 따라하기

210914 [4장] 4.3 쿠키와 세션 이해하기

코드코코 2021. 9. 14. 11:32

1. cookie.js

const http = require("http");

http.createServer((req, res) => {
    //req.headers: 요청의 헤더
    //req.headers.cookie : 쿠키가 들어 있음.
    console.log(req.url, req.headers.cookie);
    //응답의 헤더에 쿠키를 기록해야 하므로 res.writeHead사용
    //set-Cookie : 브라우저에세 다음과 같은 쿠키 값을 저장하라는 의미
    //실제로 응답받은 브라우저는 mycookie=test라는 쿠키를 저장.
    res.writeHead(200, { "set-Cookie": "mycookie=test" });
    res.end("Hello cookie");
}).listen(8088, () => {
    console.log("8088번 포트에서 서버 대기 중입니다!");
});

//쿠키는 요청과 응답의 헤더를 통해 오고 감.

2-1. cookie2.js

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

//parseCookies : 문자열을 자바스크립트 개체 형식으로 바꿈.
const parseCookies = (cookie = "") =>
    cookie
        .split(";")
        .map((v) => v.split("="))
        .reduce((acc, [k, v]) => {
            acc[k.trim()] = decodeURIComponent(v);
            return acc;
        }, {});

http.createServer(async (req, res) => {
    const cookies = parseCookies(req.headers.cookie);

    //주소가 /login으로 시작하는 경우
    if (req.url.startsWith("/login")) {
        const { query } = url.parse(req.url);
        const { name } = qs.parse(query);
        const expires = new Date();
        //쿠키 유효 시간을 현재 시간 +5분으로 설정
        expires.setMinutes(expires.getMinutes() + 5);
        res.writeHead(302, {
            location: "/",
            //헤더에는 한글을 설정할수 없음.
            //Set-Cookie 값으로 제한된 ASC2코드만 가능해서 줄바꿈 안됨.
            //name 변수를 encodeURIComponent메서드로 인코딩.
            //Expires과 HttpOnly, Path 같은 옵션 부여
            "Set-Cookie": `name=${encodeURIComponent(
                name
            )}; Expires=${expires.toGMTString()}; HttpOnly; path=/`,
        });
        res.end();

        //name이라는 쿠키가 있는 경우
    } else if (cookies.name) {
        res.writeHead(200, { "content-Type": "text/plain; charset=utf-8" });
        res.end(`${cookies.name}님 안녕하세요.`);
        //그외의 경우(/로 접속했을 때 등)
    } else {
        try {
            const data = await fs.readFile("./cookie2.html");
            res.writeHead(200, { "content-Type": "text/html; charset=utf-8" });
            res.end(data);
        } catch (err) {
            res.writeHead(500, { "content-Type": "text/plain; charset=utf-8" });
            res.end(err.message);
        }
    }
}).listen(8084, () => {
    console.log("8084번 포트에서 서버 대기 중 입니다!");
});

/*
cookie

1. 저장위치 : 웹브라우저(클라이언트)
2. 쿠키명 = 쿠키값
3. Expires = 날짜 : 만료기한, 기본값은 클라이언트가 종료될 때까지
4. Max-age = 초 : Expires와 비슷하지만 날짜 대신 초 입력. Expires보다 우선.
5. Domain = 도메인명 : 쿠키가 전송될 도메인을 특정. 기본값은 현재 도메인.
6. Parh = URL : 쿠키가 전송될 URL 특정. 기본값은 '/'이고, 이 경우 모든 URL에서 쿠키를 전송할 수 있음.
7. Secure : https일 경우만 쿠키 전송
8. HttpOnly: 해당 설정시 자바스크립트에서 쿠키에 접근불가. 쿠키조작방지를 위해 설정권장.

*/

2-2. cookie2.html

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>쿠키&세션 이해하기</title>
</head>
<body>
    <form action="/login">
        <input id="name" name="name" placeholder="이름을 입력하세요">
        <button id="login">로그인</button>
    </form>    
</body>
</html>

 

3. session.js

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

//parseCookies : 문자열을 자바스크립트 개체 형식으로 바꿈.
const parseCookies = (cookie = "") =>
    cookie
        .split(";")
        .map((v) => v.split("="))
        .reduce((acc, [k, v]) => {
            acc[k.trim()] = decodeURIComponent(v);
            return acc;
        }, {});

const session = {};

http.createServer(async (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 uniqueInt = Date.now();

        //사용자의 이름과 만료시간은 uniqueInt속성멸 아래에 있는
        //session이라는 객체에 대신 저장.
        session[uniqueInt] = {
            name,
            expires,
        };
        res.writeHead(302, {
            Location: "/",
            "Set-Cookie": `session=${uniqueInt}; Expires=${expires.toGMTString()}; HttpOnly; Path=/`,
        });
        res.end();
        //세션 쿠키가 존재하고, 만료 기간이 지나지 않았다면
    } else if (
        cookies.session &&
        session[cookies.session].expires > new Date()
    ) {
        res.writeHead(200, { "content-Type": "text/plain; charset=utf-8" });
        res.end(`${session[cookies.session].name}님 안녕하세요`);
    } else {
        try {
            const data = await fs.readFile("./cookie2.html");
            res.writeHead(200, { "content-Type": "text/html; charset=utf-8" });
            res.end(data);
        } catch (err) {
            res.writeHead(500, { "content-Type": "text/plain; charset=utf-8" });
            res.end(err.message);
        }
    }
}).listen(8085, () => {
    console.log("8085번 포트에서 서버 대기 중입니다.");
});

/*
session 

1. 저장위치 : 서버
2. 세션쿠키 : 세션을 위해 사용하는 쿠키, 꼭 쿠키를 사용해야 하는 것은 아니지만 많은 웹들이 쿠키사용.
3. 보통은 에디스나 맴캐시드 같은 데이터베이스에 저장.

 */