쿠키는 웹 브라우저에 저장되는 값이다. 고로 브라우저를 종료해도 해당값 보존된다. 브라우저를 껐다 켜는 것과 상관없이 특정 상태가 유지되는 예시로 뭐가 있을까? 먼저 자동 로그인이나 아이디 저장이 있겠다.
또 다른 예시로는 '오늘만 보지 않기' '일주일 간 보지 않기' 같은 팝업창이다.
이런 경우는 만료일을 설정하여 특정 기간에만 쿠키를 동작하게 한다. 직접 삭제하는 방식으로도 쿠키를 제거할 수 있다.
쿠키를 프론트와 백 모두 생성할 수 있는데, 클라이언트-서버 방식으로 개발을 진행한다면 프론트에서 독자적으로 생성과 사용을 하지 말고 서버에서 쿠키를 생성해 이를 포함하여 응답으로 전달하는 게 좋다. 주거니받거니!
개발자도구의 애플리케이션 혹은 응용프로그램에서 찾아볼 수 있다.
이름, 값, 도메인, 경로, 만료일 등으로 구성되었다.
res.send
은 별개이므로 클라이언트에 보낼 응답이 있다면 쿠키와 별개로 작성해줘야 한다.)이걸 직접 사용하려면 모듈 설치부터 해줘야 한다.
npm i cookie-parser
이걸 불러와 미들웨어로 걸어주면 사용할 수 있다.
일전에 쿠키는 이름, 값, 도메인, 경로, 만료일 등으로 구성되었다고 했다. 서버에서 응답으로 쿠키를 돌려줄 때에 이름, 값, 만료일을 포함한 옵션을 인자로 넘겨준다.
옵션은 객체로 만들어 보내는데, 몇 가지 자주 사용하는 키를 소개하자면 아래와 같다.
httpOnly
: 기본값은 false다. true 값 설정 시 자바스크립트에서 document.cookie와 같은 DOM 방식으로 쿠키에 접근할 수 없다. 즉 서버에서만 쿠키를 조작할 수 있다. 클라이언트에 저장되었는데도 말이다.
maxAge
: ms단위로 만료일을 설정한다. 연산식으로도 작성 가능해서 만약 24시간을 설정하고 싶다면 작은 단위로 쪼갠다고 생각하자. 1시간은 60분이고, 1분은 60초고, 1초는 1000밀리초다. 즉 24 * 60 * 60 * 1000
으로 작성하면 된다.
만약 모든 유저에게 일괄적으로 설정하고 싶다면 expires
키를 사용한다. 이건 full로 날짜 입력후 T 뒤에 원하는 시간을 24시간제로 입력하면 된다. 따옴표 잊지 말자.
ex. '2023-11-08T20:00'
path
: 쿠키 설정할 경로를 지정할 수 있다. 예를들어 /search
라고 입력했다면, url이 http://naver.com/search
부터 해당된다. http://naver.com/
같은 경로는 해당 쿠키가 생기지 않는단 의미다.
secure
: 기본값 false. true일 시, 보안 서버인 https에서만 쿠키를 동작할 수 있게 한다.
signed
: 기본값 false. true면 쿠키를 암호화하는데 req.signedCookies
에서 조회할 수 있다.
const cookieParser = require('cookie-parser');
app.use(cookieParser());
app.use('view engine', 'ejs');
const cookieConfig = {maxAge: 30000};
app.get('/', (req, res) => {
res.render('index');
});
app.get('/set', (req, res) => {
res.cookie('key', 'value', cookieConfig)
res.send('set cookie')
});
1) 먼저 cookie-parser 모듈을 불러와 미들웨어로 걸어줬다. 서버에서 쿠키를 읽고 해석하기 위함이다.
2) 옵션으로 설정할 객체를 cookieConfig라는 변수로 만들었는데 30000인 걸 보아하니 30초가 만료기간이다. 즉 쿠키 생성하고 30초 지나면 쿠키가 사라진다.
3) /set 라우터에 접속하면 30초 만료인 쿠키가 생성된다. 화면에는 set cookie라는 글자를 띄울 모양이다.
ejs를 뷰 엔진으로 쓴다면 기본적으로 views 폴더 안으로 경로가 설정되어있다. 그런데 해당 폴더에 넣지 않았다면 에러가 발생하고 만다. 이걸 몰랐어서 수업 중에 잠시 애먹었다.
아래는 제대로 접속해서 쿠키를 생성한 모습이다.
🔸 쿠키는 만료 전까지 클라이언트에 계속 남아있어서 생성 이후로는 쿠키가 포함된 상태로 서버에 request한다. 그런데 현재 상태에서 정보를 업데이트할 필요가 있다면? 당연히 쿠키도 업데이트하여 HTTP 헤더 포함한 후 응답한다.
🔸 자동 로그인, 아이디 저장, 기간 팝업창 같은 데이터를 매번 서버에 저장한다면 메모리 부담이 상당해 성능에 문제가 발생할 여지가 높다. 그래서 클라이언트에 저장해두는 거다.
🔸 클라이언트는 브라우저별로 존재한다. 즉 엣지와 크롬은 각각의 클라이언트다. 여기에 시크릿모드까지 사용한다면 총 4개의 클라이언트를 활용할 수 있다.
하루 동안 보지 않기 모달창을 구현하려고 한다. 체크박스를 선택하고 닫기 버튼을 눌렀다면 새로고침 하거나 브라우저 종료 후 재접속 해도 만료 기간인 하루가 지나기 전엔 모달창이 뜨지 않아야 한다. 즉 프론트 단에서 쿠키가 있을 경우엔 모달 창을 보여주지 않는다는 조건을 달아줘야 한다.
이때 옵션객체에 httpOnly: true 값을 넘긴 케이스라고 하자. 프론트 단에서 document.cookie
로 쿠키 유무를 파악할 수 없다. 그럼 어떻게 할까? 서버에서는 res.cookie
를 통해 쿠키를 생성해 결과로 보내고, req.cookies.쿠키 이름
으로 클라이언트에 있는 쿠키를 받아온다.
이걸 활용해 서버 측에서 쿠키 존재 여부를 담은 변수를 전달하면 되겠다. {result: req.cookies.만든 쿠키 이름}
ejs를 사용 중이라면 ejs 문법으로 그 변수를 가져올 수 있다. 그런데 JS의 조건문 안에서 사용해야 하니까 변수를 문자열로 감싸줘야 한다.if (!'<%= result %>')
웹 서버에 저장되는 쿠키라고 보면 된다. 서버에 저장하기 때문에 브라우저를 종료하면 해당 저장값도 사라진다. 대표적인 예시는 로그인 유지 기능이 있겠다. 로그아웃 버튼을 누르지 않아도 창을 완전히 닫기만 하면 다시 접속했을 때 로그인이 되어있지 않은 걸 본 적 있을 거다.
클라이언트가 서버 접속 시 세션 ID 발급 🔑
(앞서 언급했듯 브라우저 각각 다른 클라이언트로 인식해서 세션 ID가 다르다)
세션 ID를 클라이언트에 저장 후 서버에 요청할 때 ID도 서버에 전달
서버는 세션 ID로 세션에 있는 클라이언트 정보 가져와서 응답
쿠키와 마찬가지로 모듈을 설치해준다.
npm i express-session
쿠키는 빈 인자로 호출하고 따로 변수를 만들어 설정해줬는데, 세션은 아예 미들웨어 걸 때부터 객체를 생성해 설정해준다. 이때에 자주 쓰는 키도 알아보자.
secret
: 컴퓨터가 세션에 접근할 수 있게 해주는 작업.
resave
: 요청이 있을 때마다 세션을 다시 저장할지.
saveUninitialized
: 클라이언트가 처음 접속할 때 세션을 초기화할지.
cookie
: httpOnly, maxAge, secure 등 쿠키에서 쓰던 key를 그대로 쓸 수 있다. 만료 시간을 설정해두면 10분 간 활동 없을 시 자동 로그아웃 같은 기능을 넣을 수 있다.
마찬가지로 30초 만료 기간을 두고 세션을 만들어본다.
const session = require('express-session');
app.use(session({
secret: 'secret key',
resave: false,
saveUninitialized: true,
cookie: {
httpOnly: true,
maxAge: 30000
}
}));
app.get('/', (req, res) => {
res.send('Hello world!')
})
app.get('/set', (req, res) => {
req.session.user = 'une'
res.send("set session");
})
app.get('/get', (req, res) => {
res.send({id:"", user: req.session.user});
})
app.listen(port, () => {
console.log(`${port} is open`)
})
세션은 req.session.세션이름
에 값을 할당해 이를 저장한다. 세션은 브라우저가 종료되면 자동으로 사라지긴 하지만, 유저가 로그아웃 버튼을 누를 때에도 세션을 삭제해줘야 할 것이다. 이때 destroy 메서드를 이용한다.
// 생략
req.session.destroy((err) => {
if(err) throw err;
res.send({result: true, msg:'로그아웃 되었습니다.'});
})
에러가 있는지 확인하고, 없을 경우엔 프론트 단에 로그아웃을 판별할 수 있는 플래그 역할의 값과 유저에게 보여줄 메시지도 같이 전달한다.
세션 로그아웃 기능을 애먹으면서 풀었던 것 같은데 막상 복습해보니 쿠키는 기억이 선명한데 세션 부분이 흐릿하다. 유저 로그인 유지를 세션으로 구현하려면 어떻게 했더라..
세션은 전역에 생성해야 하니까 index.js에서 객체를 생성한다. 유저가 로그인할 때 유저 레코드 중 PK를 req.session.새이름
에 할당한다.
세션 값을 기준으로 유저의 로그인 상태를 value로 넣어서 id 값 등을 프로필 화면에 보여주거나 유저가 작성한 글 확인 등을 허용한다.
요 내용을 이번 프로젝트에서 구현해봐야지~! 재밌겠다.