본문 바로가기

Programming/Node.js

5. http 모듈로 서버 만들기 (3) - 쿠키와 세션의 이해 [5]

node js logo image

 

 

 

 

앞선 아티클에서 계속 이어서 코드를 살펴보겠습니다.

 

[cookie2.html]

<!DOCTYPE html>
<head>
    <meta charset="UTF-8">
    <title>COOKIE & SESSION SAMPLE</title>
</head>
<body>
    <form action="/login">
        <input id="name" name="name" placeholder="enter the name" />
        <button id="login">LOGIN</button>
    </form>
</body>
</html>

 

 

 

[cookie2.js]

const http = require('http');
const fs = require('fs').promises;
const path = require('path');

// *1번 시작
const parseCookies = (cookie = '') => 
    cookie
        .split(';')
        .map(v => v.split('='))
        .reduce((acc, [k, v]) => {
            acc[k.trim()] = decodeURIComponent(v);
            return acc;
        }, {});
// 1번 끝*

// *2번 시작
http.createServer(async (req, res) => {
    const cookies = parseCookies(req.headers.cookie);

    // 주소가 /login으로 시작하는 경우
    if(req.url.startsWith('/login')) {
        const url = new URL(req.url, 'http://localhost:8084');
        const name = url.searchParams.get('name');
        const expires = new Date();
        // 쿠키의 유효 시간은 현재 시각 + 5분으로 설정한다.
        expires.setMinutes(expires.getMinutes() + 5);
        res.writeHead(302, {
            Location: '/',
            'Set-Cookie': `name=${encodeURIComponent(name)}; Expires=${expires.toGMTString()}; HttpOnly; Path=/`,
        });
        res.end();
// 2번 끝*

// *3번 시작
        // 주소가 /이면서 name이라는 쿠키가 있는 경우
    } else if (cookies.name) {
        res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
        res.end(`${cookies.name}님 안녕하세요`);
    } else { // 주소가 /이면서 name이라는 쿠키가 없는 경우
        try {
            const data = await fs.readFile(path.join(__dirname, '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);
        }
    }

})	// 3번 끝*
    .listen(8084, () => {
        console.log('8084번 포트 서버 대기 중');
    });

 

 

 

1번 코드 영역에서 쿠키가 mycookie=test와 같은 문자열 타입의 데이터에 JS 객체 타입으로 변환된다는 것을 확인했습니다. 형식은 { mycookie: 'test' }와 같다고 했죠. 

 

2번 코드 영역은, 로그인 요청(GET /login)을 처리합니다. cookie2.html 파일을 보면 해당 form의 action 속성 값이 "/login"으로 설정되어 있습니다. 기본적으로 form은 GET req일 경우 데이터를 쿼리스트링으로 보냅니다. 그래서 쿼리스트링 부분을 URL 객체로 분석했죠. 여기에 쿠키의 유효 시간을 5분으로 설정까지 해두었습니다. 코드 자체가 다소 복잡하니, 전체적인 틀만이라도 이해하고 진행합시다. 

 

이제 res.writeHead를 보면 302 응답코드를 사용합니다. 페이지를 리다이렉트 한다는 의미죠? 그 주소는 다름아닌 '/' 입니다. 이제 첫 로그인 기록으로 발생한 쿠키를 res의 헤더에 넣어서 보냅니다. Set-Cookie를 통해 보내게 되죠(자세한 양식은 아래에 다시 설명합니다). 결국 브라우저는 이 응답 코드를 보고, 페이지를 해당 주소로 리다이렉트하는 결과를 가져옵니다. 

 

참고로 헤더에는 한글 설정이 불가합니다. 그래서 name 변수를 encodeURIComponent로 인코딩 합니다. 또한 Set-COokie의 값으로는 제한된 아스키 코드만 들어가야 하므로 줄바꿈을 넣어서는 안됩니다.

 

3번 코드 영역도 살펴보겠습니다. 1, 2번의 경우를 제외한 경우 접속했을 때(/로 접속하는 경우) 쿠키가 있는지 없는지 여부를 확인하게 됩니다. 만일 쿠키가 없는 경우, 로그인이 가능한 페이지를 보내주게 됩니다. 처음 방문해 쿠키가 없다면 cookie2.html을 전송하고, 쿠키가 있다면 로그인 상태로 간주하며 인사말을 출력하게 됩니다. 

 

 

위 코드에서 Set-Cookie를 통해 쿠키 값을 설정을 진행했습니다. 여기서 사용된 속성 값들에 대해서 다음 아티클을 통해 자세히 살펴보겠습니다.