[Node.js]-Cookie & Session
Updated:
Cookie 와 Session
=> 이 게시글은 로그인을 구현하기 위한 사전지식으로 Cookie와 Session에 대해 알아본다
Cookie
-> 클라이언트가 보내는 요청에는 ‘누가 이 요청을 보내는지’에 관한 정보가 빠져있다. 이 ‘누가’를 알아내기 위해 로그인을 구현할 필요가 있고, 바로 로그인을 구현하기 위해서 Cookie와 Session이 필요하다
-> 이 ‘누구’를 식별하기 위해 서버가 먼저 쿠키를 응답과 함께 클라이언트에게 보낸다. 클라이언트는 이후부터 무언가 요청할때마다 쿠키를 헤더에 동봉해서 함께 보낸다. 즉, 서버에서 클라이언트로 쿠키를 보낼때만 코드를 작성해주면 된다. 여기서 쿠키는 ‘key-value’쌍의 형태를 지닌다
간단 예제
const http = require('http');
http.createServer((req, res)=>{
console.log(req.url, req.headers.cookie);
res.writeHead(200, {'Set-Cookie': 'myCookie=lim'});
res.end('Send Cookie');
}).listen(8080, ()=>{
console.log('서버가 8080포트에서 실행중~');
})
-> req.headers.cookie를 통해 쿠키를 가져올 수 있다
-> res.writeHead(200, {‘Set-Cookie’: ‘myCookie=lim’}) 와 같이 서버에서 클라이언트 측으로 쿠키를 보내면 된다

-> 위와 같이 개발자 도구의 Network탭에서 Headers부분을 살펴보면 Set-Cookie값이 코드에서 작성한 것과 같이 설정되었음을 확인할 수 있다
-> 서버에서 클라이언츠 측으로 한번만 쿠키를 보내주면, 그 이후부터는 자동으로 클라이언트 측에서 서버로 쿠키를 보내주는데, 이를 Network탭의 Request Headers에서 확인할 수 있다
실전 예제
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<title>Cookie & Session</title>
</head>
<body>
<form action="/login">
<input id="name" name="name" placeholder="이름을 입력하세요." />
<button id="login">로그인</button>
</form>
</body>
</html>
const http = require('http');
const fs = require('fs').promises;
const path = require('path');
const parseCookies = (cookie = '')=>{ // 헤더에서 쿠키 찾아오는 함수
return cookie
.split(';')
.map(e => e.split('='))
.reduce((acc, [k,v])=>{
acc[k.trim()] = decodeURIComponent(v);
return acc;
}, {});
};
http.createServer(async (req, res)=>{
const cookies = parseCookies(req.headers.cookie);
if(req.url.startsWith('/login')){ // url이 /login일 경우
const url = new URL(req.url, 'http://localhost:8084');
const name = url.searchParams.get('name');
const expires = new Date();
expires.setMinutes(expires.getMinutes() + 5);
res.writeHead(302, {
Location: '/',
'Set-Cookie': `name=${encodeURIComponent(name)}; Expires=${expires.toGMTString()}; HttpOnly; Path=/`,
});
res.end();
} else if(cookies.name){ // 쿠키가 이미 존재할 경우
res.writeHead(200, {'Content-Type': 'text/plain; charset=utf-8'});
res.end(`${cookies.name}님 안녕하세요!`);
} else{ // 쿠키가 존재하지도 않고 /login으로 접근하지도 않을 경우
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);
}
}
}).listen(8084, ()=>{
console.log('서버가 8084포트에서 실행중~');
});
-> ‘url이 /login일 경우’, ‘쿠키가 이미 존재할 경우’, ‘쿠키가 존재하지도 않고 url이 /login이 아닐경우’ 3가지로 나눠 처리하는 코드이다
-> 처음으로 ‘localhost:8084/’로 접근할 경우, ‘cookie.html’ 파일로 이동하며, 로그인페이지가 나타난다. 로그인페이지에서 로그인 버튼을 누르면, GET요청이므로 data는 /login뒤에 query string형식으로 들어간다
-> 이후 url.searchParams를 통해 query string을 가져와 get()으로 특정 파라미터를 추출한다
-> res.writeHead(302)는 리다이렉션을 의미하고, Location으로 리다이렉션할 주소를 적으면 된다
-> ‘Set-Cookie’ 의 속성 중 Expires를 설정하지 않을 경우, 브라우저가 종료되면 쿠키가 사라진다. 또한, HttpOnly 속성을 통해 JS에서 쿠키에 접근할 수 없도록 막는다
Session
-> Cookie 방식을 사용하면, 어느 쿠키를 가지고 있는지 브라우저의 개발자도구로 확인이 가능하므로, 누가 로그인을 했는지 모두 드러난다
-> 이를 해결하기 위해 서버에 사용자 정보를 저장하고, 클라이언트에게 세션아이디 같은 key값만 제공하는 방식을 Session이라고 한다
const http = require('http');
const fs = require('fs').promises;
const path = require('path');
const parseCookies = (cookie = '')=>{
return cookie
.split(';')
.map(e => e.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 url = new URL(req.url, 'http://localhost:8085');
const name = url.searchParams.get('name');
const expires = new Date();
expires.setMinutes(expires.getMinutes() + 5);
const uniqueInt = Date.now();
console.log(uniqueInt);
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(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);
}
}
}).listen(8085, ()=>{
console.log('서버가 8085포트에서 실행중~');
});
-> 위의 Cookie 코드와 비슷한데, unique한 id값으로 구분되는 session이란 객체를 만들어서 그 안에 name과 expire정보를 담는다는 차이점이 존재한다
-> 마찬가지로, res.writeHead시에 302로 보내는데, 여기서 ‘Set-Cookie’의 session속성값으로 name이 아닌 id값을 보낸다는 차이가 있다
-> 해당 id값은 cookies.session으로 접근가능하고, session[cookies.session]으로 해당 id의 사용자 정보에 접근할 수 있다
Leave a comment