• 카테고리

    질문 & 답변
  • 세부 분야

    풀스택

  • 해결 여부

    해결됨

cookie parser 질문드립니다(소스코드 2차 수정했습니다)

22.04.28 18:51 작성 조회수 275

0

강사님 안녕하세요

소스코드를 수정해서 다시 질문드리고 싶습니다(app.js 를 수정했습니다)

 

아래는 app.js입니다

/**
 * ch6.1
 */
 const express = require('express');
 const path = require('path');
 const { nextTick } = require('process');
 const morgan = require('morgan');
 const cookieParser = require('cookie-parser');
 
 const app = express();
 app.set('port', process.env.PORT || 3000); //'port' 라는 속성에 포트번호 3000번을 설정합니다.
 //서버의 포트를 3000번으로 지정하는 것 같습니다.
 // 이 속성은 아래 19행처럼 가져올 수 있습니다
 
 //app.use(morgan('dev'));
 app.use(cookieParser());
 
 app.get('/login', (req, res, next) => {
   if(req.url.startsWith('/login')){
   req.cookies // 쿠키 객체화  
   res.cookie('name', encodeURIComponent(name2),{
     expires: new Date(),
     httpOnly: true,
     path: '/',
   })
  }
   else if(true)
   {
   next('route');
   }
   else{
     next();
   }
 }, (req, res, next)=>{
   console.log('실행되지 않음1')
   next();
 },(req,res,next)=>{
   console.log('실행되지 않음2')
   next();
 });
 
 app.get('/', (req, res) => {
   // res.send('Hello, Express');
   console.log('실행되지 않음3')
   res.sendFile(path.join(__dirname, '/cookie2.html'));
 });
 
 app.use((err,req,res,next)=>{
   console.log(err);
   res.status(200).send('에러났지롱')
 })
 
 app.listen(3000, () => {
   console.log(app.get('port'), '번 포트에서 대기 중');
 });

아래는 cookie2.html 입니다

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>쿠키&세션 이해하기</title>
</head>
<body>
<form action="/">
    <input id="name" name="name2" placeholder="이름을 입력하세요" />
    <button id="login">로그인</button>
</form>
</body>
</html>

이렇게 로그인을 해봤습니다

 

 

그런데 name2는

 

이렇게 cookie2.html에 있는데, 혹시 어디가 문제인지 도와주시면 감사하겠습니다

도저히 모르겠습니다

답변 1

답변을 작성해보세요.

0

  res.cookie('name', encodeURIComponent(name2),
여기있네요.

넵 그런데 cookie2.html 에서 name2 에 아이디를 담아서 app.js에 보내주는데, 왜 name2가 정의되지 않았다고 하는지 이해가 어렵습니다

이게 html 파일이구요

아래가 원래 cookie2.js 파일인데요

 

저는 왼쪽의 node 코드가 오른쪽의 express 코드와 대응된다고 생각했습니다

 

1대1 대응이 잘못된 부분을 가르쳐주시면 감사하겠습니다

 

제가 이 부분을 하루종일 고민하고 있어서 가르쳐주시면 참 좋을 것 같아요ㅠㅠ
강의를 다시 들어도 강사님 강의에서도 익스프레스 코드에서 변수 name을 따로 정의하지는 않은 것 같아서요

아니면 app.js 코드를 일부분 수정해주시면 제가 이해해보려고 노력할게요

쿠키가 안생겨서요..

const name2를 해야 선언이되죠. 서버는 프론트가 어떻게 생겼는지 모릅니다. 오로지 요청 객체에 든 정보만으로 아는 겁니다. 서버는 프론트에서 name2라는걸 보내는지 아예 알 수가 없어요.

req.cookies.name2 를 하셔야죠

쿠키가 안 생기는 건 코드에 에러가 있어서 res.cookie까지 실행이 안 되니까 안 생겼겠죠

선생님 고맙습니다 그런데 저도 뒤늦게 req.cookies.name2로 받아주었는데요

req.cookies가 아무것도 안받아주더라구요 ㅠㅠ

res.cookie 요? 이걸 해결해주면 req.cookies도 빈객체가 안될 수 있을까요 

강의 다시 듣겠습니다 ㅠㅠ

선생님 다시 들어도 모르겠습니다

이거 res.cookie까지 실행해주는 것 같은데여

 

그런데 모르겠어요 ㅠㅠ

익스프레스도 생략된 게 많으니 promise 처음 공부할 때처럼 갈피가 안잡히네요

힌트 하나만 더 주시면 안될까요?

현재 app.js 소스코드입니다

/**
 * ch6.1
 */
 const express = require('express');
 const path = require('path');
 const { nextTick } = require('process');
 const morgan = require('morgan');
 const cookieParser = require('cookie-parser');
 
 const app = express();
 app.set('port', process.env.PORT || 3000); //'port' 라는 속성에 포트번호 3000번을 설정합니다.
 //서버의 포트를 3000번으로 지정하는 것 같습니다.
 // 이 속성은 아래 19행처럼 가져올 수 있습니다
 
 //app.use(morgan('dev'));
 app.use(cookieParser());
 
 app.get('/login', (req, res, next) => {
   if(req.url.startsWith('/login')){
   req.cookies // 쿠키 객체화  
   res.cookie('name', encodeURIComponent(req.cookies.name2),{
     expires: new Date(),
     httpOnly: true,
     path: '/',
   })
  }
   else if(true)
   {
   next('route');
   }
   else{
     next();
   }
 }, (req, res, next)=>{
   console.log('실행되지 않음1')
   next();
 },(req,res,next)=>{
   console.log('실행되지 않음2')
   next();
 });
 
 app.get('/', (req, res) => {
   // res.send('Hello, Express');
   console.log('실행되지 않음3')
   res.sendFile(path.join(__dirname, '/cookie2.html'));
 });
 
 app.use((err,req,res,next)=>{
   console.log(err);
   res.status(200).send('에러났지롱')
 })
 
 app.listen(3000, () => {
   console.log(app.get('port'), '번 포트에서 대기 중');
 });

 

강사님께서 제게 생각하는 힘을 길러주시기 위해, 힌트를 주시는 것도 느껴집니다

그런데, 도저히 모르겠습니다

강사님이시라면, 어떻게 소스코드를 변경하실 것인지
강사님의 app.js 소스코드를 보여주신다면

cookie2.html 과 연동시켜 실행시켜본 다음

궁금한 부분을 다시 질문드리고 싶습니다

그렇게 해주시면 참 감사할 것 같습니다

저는 학기 중이어서 시간이 충분치가 못해서 우선 다음 진도로 넘어가야할 것 같아요 ㅠㅠ

아래 사진에서

console.log 로 req.cookies.name2 출력했는데 undefined가 나옵니다

 

아, req.query.name2 입니다. 쿼리스트링으로 데이터가 들어오니까요.

선생님 가르쳐주셔서 정말 감사합니다

그런데 혹시.. 쿠키가 안들어가는 이유도 질문드려도 되나요?

저는 경로가 달라서 쿠키가 안보이는 것 같았습니다

그래서 경로를 똑같이 /으로 해봤습니다

그래도 쿠키는 보이지 않았습니다

res.cookie('name', encodeURIComponent(req.query.name2),{
     expires: new Date(),
     httpOnly: true,
     path: '/',
 })

를 했는데도 웹브라우저에 쿠키가 안담긴 이유를 가르쳐주시면 정말 감사하겠습니다

읽어주셔서 감사합니다

 

네트워크 탭에서 /login 요청의 응답 헤더쪽을 살펴보세요. Set-Cookie 헤더가 있어야 합니다. 한 가지 걸리는 것은 expires가 지금시간입니다. 즉, 쿠키를 만들자마자 만료된다는 것입니다.

아 그렇군요! 감사합니다
아래의 22, 24행 처럼 쿠키만료시간을 5분을 주도록 소스코드를 변경해봤습니다

 

 

그런데, 아직 네트워크의 응답헤더 쪽에서 쿠키가 안보여서

응용프로그램쪽을 찾아봤는데도, 안보여서

혹시 제가 잘못 입력한 소스코드가 있는지 가르쳐주시면 감사하겠습니다

 

/**
 * ch6.1
 */
 const express = require('express');
 const path = require('path');
 const { nextTick } = require('process');
 const morgan = require('morgan');
 const cookieParser = require('cookie-parser');
 
 const app = express();
 app.set('port', process.env.PORT || 3000); //'port' 라는 속성에 포트번호 3000번을 설정합니다.
 //서버의 포트를 3000번으로 지정하는 것 같습니다.
 // 이 속성은 아래 19행처럼 가져올 수 있습니다
 
 //app.use(morgan('dev'));
 app.use(cookieParser());
 
 app.get('/login', (req, res, next) => {
   if(req.url.startsWith('/login')){
   req.cookies // 쿠키 객체화  
   console.log(req.query.name2)
   expires.setMinutes(expires.getMinutes()+5);
   res.cookie('name', encodeURIComponent(req.query.name2),{
     expires: expires.toGMTString(),
     httpOnly: true,
     path: '/',
   })
  }
   else if(true)
   {
   next('route');
   }
   else{
     next();
   }
 }, (req, res, next)=>{
   //console.log('실행되지 않음1')
   next();
 },(req,res,next)=>{
   //console.log('실행되지 않음2')
   next();
 });
 
 app.get('/', (req, res) => {
   // res.send('Hello, Express');
   //console.log('실행되지 않음3')
   res.sendFile(path.join(__dirname, '/cookie2.html'));
 });
 
 app.use((err,req,res,next)=>{
   console.log(err);
   res.status(200).send('에러났지롱')
 })
 
 app.listen(3000, () => {
   console.log(app.get('port'), '번 포트에서 대기 중');
 });

expires는 갑자기 어디서 튀어나오는 건가요? 선언도 없이? 이건 자바스크립트입니다. 명심하세요.

유효기간 설정하는 코드는 제가 4강에서 다 보여드렸습니다.

아 제가 기본적인 실수를 저질렀네요..
선생님 강의를 다시 들으면서 https://www.inflearn.com/course/%EB%85%B8%EB%93%9C-%EA%B5%90%EA%B3%BC%EC%84%9C/lecture/56895?tab=curriculum

9행에 선언하는 코드를 넣었습니다

 

그래도 쿠키가 생성이 잘 안되어서..

 

그 혹시.. 또 질문드려도 되나요?

 

 

일단 코드를 좀 정상적으로 만들어주세요. next('route')같은 것 하지 마시고요. 일반 프로그래머가 라우터 만들듯 만드세요. 그리고 const expires는 9행이 아니라 20행 이렇게 라우터 안에 만드셔야합니다. 9행에 만들면 서버를 켠 시간이 저기에 기록되는 겁니다.

지금 라우터 코드가 최종적으로 에러 처리 미들웨어로 가고 있습니다. 정상적인 응답을 하세요.

제가 질문을 많이 드리는 수강생이기도 하고, 그래서 감사한 마음도 가지고 있습니다

그리고 익스프레스 부분이 상당히 어렵긴 하더라구요

그래서 http 모듈 때 배운 cookie.html 소스코드에 적용해봐야겠다는 생각을 했어요

제 소스코드가 비정상으로 보이는지는 몰랐습니다. 배운지 얼마 안된 개념들이라서 뭔가를 만들어내는 게 익숙하지 못했습니다

 

강사님이 배포해주신 cookie2.js 를 제 나름대로 익스프레스 코드로 만들어볼게요

강사님은 제게 항상 도움주신 입장이니까 그동안 참으시고 말씀 안하신 것도 있을 것 같네요 앞으로는 좀더 소스코드를 예쁘게 짜서 질문드릴게요

19번째 줄 if문도 express에서는 필요가 없고요. next()로 다음 미들웨어로 넘어가는 것도 마지막 라우터에서는 거의 하지 않는 동작입니다.

요청을 받아서 처리 후 응답을 보내는 깔끔한 동작만 하면 됩니다. next()나 next('route')는 예전에 미들웨어 성질 알아보려고 실습할 때 했던 코드잖아요. 그런 걸 남겨둘 필요가 없죠.

코드가 복잡하고 군더더기가 많을수록 파악도 어렵고 에러가 많이 나는 법입니다. 싹 지우고 필요한 것만 넣으세요. cookie2.js와 같은 기능을 하되 쓸모없는 부분은 다 쳐낸 코드가 좋은 코드입니다.

네 선생님 최대한 익스프레스로 변경해봤는데.. 잘 모르겠어서 죄송합니다

그리고 19행 if문이 필요 없다고 말씀해주셔서요

혹시18행에서 '/login:name' 으로 변경해주면 되나요..?

 

아래 소스코드는 cookie2.js 를 익스프레스 소스코드로 변경해봤는데 쉽지 않네요 ㅠㅠ

어디가 문제인지 잘.. 모르겠습니다

 
 const express = require('express');
 const path = require('path');
 const { nextTick } = require('process');
 const morgan = require('morgan');
 const cookieParser = require('cookie-parser');
 
 const app = express();
 app.set('port', process.env.PORT || 3000); //'port' 라는 속성에 포트번호 3000번을 설정합니다.
 //서버의 포트를 3000번으로 지정합니다.
 
 
 //app.use(morgan('dev'));
 //쿠키를 객체화 시킵니다.
 app.use(cookieParser());

 //login 경로의 경우입니다.
 app.get('/login', (req, res, next) => {
   if(req.url.startsWith('/login')){  
   req.cookies // 쿠키 객체화  
   console.log("req.query.name "+req.query.name);
  //  expires.setMinutes(expires.getMinutes() + 5);
  const expires = new Date();
  expires.setMinutes(expires.getMinutes() + 5);
   res.cookie('name', encodeURIComponent(req.query.name),{
     expires: expires,
     httpOnly: true,  
     path: '/',
   })
   res.send();
  } 
});
 
app.get('*', (req,res)=>{
  if(req.cookies.name)//name이라는 쿠키가 있는 경우입니다.
  {
   res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
   res.send(`${req.cookies.name}님 안녕하세요`);//쿠키에 넣은 이름이 웹페이지에 출력됩니다
  }
  else{ //로그인도 아니고, 쿠키도 없는 경우입니다.
   try {
     res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
     res.sendFile(path.join(__dirname, '/cookie2.html'));//cookie2.html 파일을 클라이언트에게 보내준다
   } catch (err) {
     res.writeHead(500, { 'Content-Type': 'text/plain; charset=utf-8' });
     res.end(err.message);
  }
 }
});

//아래는 에러처리입니다.
app.use((req,res,next)=>{
  next(createError(404));
})

 app.use((err,req,res,next)=>{
  res.locals.message = err.message;
  res.locals.error = req.app.get(`env`) === `development` ? err:{};
  res.status(err.status ||500);
  res.render(`error`);
 });
 
 app.listen(3000, () => {
   console.log(app.get('port'), '번 포트에서 서버 대기 중입니다!');
 });

 

긴 질문을 읽어주셔서 고맙습니다

밤마다 조금씩 시간내서 더 고민하고 다듬어볼게요

혹시 ejs 설치하고

app.set('view engine', 'ejs'); 

app.set('views', path.join(__dirname, 'views')); 

2줄을 6행에 추가해봐도 엔진 에러가 해결이 안되어서 이 부분만이라도 먼저 가르침을 주시면 감사하겠습니다

 

 const express = require('express');
 const path = require('path');
 const morgan = require('morgan');
 const cookieParser = require('cookie-parser');
 
 const app = express();
 app.set('port', process.env.PORT || 3000); //'port' 라는 속성에 포트번호 3000번을 설정합니다.
 //서버의 포트를 3000번으로 지정합니다.
 
 app.use(morgan('dev'));
 app.use(cookieParser());

 //login 경로의 경우입니다.
 app.get('/login', (req, res) => { 
  const expires = new Date();
  expires.setMinutes(expires.getMinutes() + 5);
  res.cookie('name', encodeURIComponent(req.query.name),{
     expires: expires,
     httpOnly: true,  
     path: '/',
  })
  res.redirect('/');
});
 
app.get('/', (req,res)=>{
  if(req.cookies.name) {
    res.send(`${req.cookies.name}님 안녕하세요`); //쿠키에 넣은 이름이 웹페이지에 출력됩니다
  }
  else{ //로그인도 아니고, 쿠키도 없는 경우입니다.
   try {
     res.sendFile(path.join(__dirname, 'cookie2.html')); //cookie2.html 파일을 클라이언트에게 보내준다
   } catch (err) {
     next(err);
  }
 }
});

//아래는 에러처리입니다.
app.use((req,res,next)=>{
  next(createError(404));
})

 app.use((err,req,res,next)=>{
  res.locals.message = err.message;
  res.locals.error = req.app.get(`env`) === `development` ? err: {};
  res.status(err.status ||500).send(err.message);
 });
 
 app.listen(app.get('port'), () => {
   console.log(app.get('port'), '번 포트에서 서버 대기 중입니다!');
 });

정말 감사합니다 제 코드와 비교해보면서 이해가 어려운 부분은 강의를 다시 찾아보며 공부하겠습니다

디버깅도 계속 해보고 검토해보고 그래도 이해가 어려운 부분이 있다면 그 부분만 질문드리겠습니다

render 함수를 사용하는 것은 지양하겠습니다

 

render는 뷰 엔진이 제대로 세팅이 되었을 때 쓸 수 있습니다.

감사합니다 ㅎㅎ

강사님 안녕하세요
완성된 소스코드를 보여주신 덕분에
render 말고도 다른 문제점을 찾았는데, 제대로 이해했는지 봐주시면 감사하겠습니다

1번째로 드리고 싶은 질문은
38행, 44행 50행의 res.writeHead() 를 주석처리 해주니
[ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client 
가 사라졌습니다

그 이유는
67행에 res.status(err.status||500).send(err.message);
가 이미 있기 때문에
38행, 44행 50행의 res.writeHead() 를 쓰면 중복으로 헤더를 응답해주기 때문인지 질문드리고 싶습니다

2번째로 드리고 싶은 질문은 
res.status(err.status||500).send(err.message);
이 err.status가 500이 아니어도, 헤더를 보내주는지 궁금합니다

왜냐하면
console.log(err.status); 
res.status(err.status||500).send(err.message);

이렇게 err.status를 콘솔출력 해줄 때 undefined가 나왔을 때도

res.status(err.status||500).send(err.message); 이 줄에서
Cannot set headers after they are sent to the client  에러가 나오더라구요

그래서 헤더를 응답해준다는 생각을 가지게 되었습니다

3번째로 드리고 싶은 질문은 

|| 가 논리연산자 아닌지 질문드리고 싶습니다
res.status(err.status||500).send(err.message);
이것을 err.status가 있거나 500이면 에러메시지를 응답한다고 해석했는데..

err.status가 undefined 여서 헤더 응답하는 것 같더라구요
잘못 쓴 건지 궁금합니다

읽어주셔서 감사합니다

그리고 하나 해결하고, 또 다른 문제들도 남아있어서 파악해보려고 하면서 배우고 있어요!

res.writeHead는 익스프레스에서 쓰는 매서드가 아닙니다. http모듈에서만 쓰는 것입니다. 익스프레스에서는 res.status나 res.setHeader를 씁니다.

지금 코드를 통해서 원리를 알아내려하시는 것 같은데, 그러시면 안됩니다. 원리(공식문서)를 보고 코드를 쓰는 겁니다. 코드를 통해서 원리를 추측하니 엉터리로 추측할수밖에 없습니다.

제가 답변을 달면서 짜증이 날수밖에 없는게 공식문서를 안 보시고 코드를 아무렇게나 작성한 후 원리를 혼자만의 판단으로 만들어내니 처음부터 다시 알려드려야 해서 그렇습니다. 익스프레스 공식문서에 다 나와있습니다.

res.status(err.status||500).send(err.message);
이것을 err.status가 있거나 500이면 에러메시지를 응답한다고 해석했는데..

라고 하셨는데 이걸 왜 해석하려고 하시나요. 라이브러리 코드는 해석하는게 아닙니다. 공식문서를 보고 정확한 뜻을 찾아보는 것이지 선조들의 비문 해석하듯 뜻을 추측하는 게 아닙니다.

공식문서 보시면 저건 http status code를 err.status또는 500으로 설정하고 err.message를 body로 응답보낸다라는 걸 명확하게 알 수 있습니다. 다른 해석의 여지가 없어요.

넵.. 제가 처음 배우는 입장이라서 일부러 그러는 게 아니라, 시행착오를 많이 겪는 것 같습니다
일부러 그러는 건 정말 아닙니다
저도 한번에 이해를 못하는 제가 답답합니다
물론, 강사님이 가르쳐주시고 도움 주시는 입장이니 더 답답하시고 참다가 얘기하신 거라고 생각해요
이번에 시도해본 소스코드 변형도
강의 여러번 들어도 햇갈리는 게 많았어요
못가르치신다는 말이 아니라, 강사님처럼 잘가르치시는 분들 몇분 안계시고  제가 이해력이 부족해서요
어떻게든 이해해보려고 다양한 시도를 해본 것였어서요
일부러 짜증나시라고 그런 건 없었습니다

오잉 답글이 한타이밍 늦게 갔네요
강사님 마지막 답글을 못보고 또 같은 질문을 드렸어요

가르쳐주셔서 감사합니다
저도 좀 제가 이해력이 부족해서 스스로가 답답하고
또 힘들게 해드려서 어떻게 해야할지 모르겠습니다
다음부터는, 먼저 공식문서도 찾아보고 질문드릴게요

저도 솔직하게, 제가 한번에 변할 수 있을지 모르겠습니다
그래서 다음부터는 안그러겠다고 확답을 못드리겠어요
그렇지만 제가 여기까지 올 수 있던 것도 다 강사님의 노고 덕분인 것 알고
저보다 많이 인내하신 거 알고 감사하게 생각하고 있습니다

저도 제 이해력으로 가능할 지는 모르겠지만 변해보려고 노력할게요

그리고 공식문서 찾아보는 것 말고도, 인강도 한번씩 더 복습하고 질문드릴게요

저한테 죄송하거나 하실 필요는 없고요. 저는 효율적인 방법을 알려드리려고 하는 겁니다. 프로그래밍에서는 정확도도 중요하지만 효율도 중요하거든요. 프로그래밍 공부도 마찬가지입니다. 혼자 코드 짜서 공부하고 하는 시간도 당연히 중요하고 필요합니다. 하지만 정확한 지식을 바탕으로 혼자 코드를 짜는 게 중요합니다. 정확한 지식을 바탕으로 하려면 문서를 봐야하는 것이고요.

강사님께서 이렇게 질의응답을 해주시지 않으셨으면,
저는 정말 여기까지 못따라왔을 겁니다
그리고 가르쳐주시는 입장에서 솔직히 많이 참고 말씀하셨을 것 같아요
가르쳐주시는 입장에서 그렇게 이야기 해주신 건 이유가 있다고 생각하고 저도 변하려고 할게요
변하는 데에도 시간이 많이 들겠고, 한번에 변할 수는 없겠지만
질문 전에 먼저 문서를 찾아보고, 강의를 한번 더 복습하고
구글링도 좀 더 해보고 질문드리겠습니다
솔직하게 이야기 나눠주셔서 좋기도 했습니다