728x90

만들기에 앞서서 

이거 먼저 만들어놔야

어떤 모듈 들어가있는지 확인할 수 있어

 

만드는 법  npm init

 

수업 듣다가 놓쳐서 에러뜨길래 물어보니까

 

 

 

스크립트에 

"start" : "nodemon app"

으로 바꿔줘야 했고

 

scripts 부분에 start 속성 잊지 말고 넣어야~!!

nodemon app을 하면 app.js를 nodemon으로 실행한다는 뜻이야  

 

코드 수정하면 노드몬이 서버 자동으로 재시작함 콘솔에서 rs 입력해서 수동으로 재시작할 수 있어

(개발용으로만 하는거 권장)

 

 

 

익스프레스 쓸거니까 밑에 애들깔아줘야 저렇게 들어가는 거임

 

npm i express

npm i -D nodemon

npm i morgan cookie-parser express-session dotenv body-parser

 

한번에 여러 개 깔 수 있음 (밑줄친건 안깔았나? 보면 없어서 안깔은거같기도 하고..)

 

원래 로그인페이지만 따라 만들고

과제로 다른 페이지로 넘어가는 거 함. 

 

일단 결과물

 

 

 

 

로그인 페이지 login.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>Document</title>
  </head>
  <body>
    <h1>Login Page</h1>
    <hr />
    <form method="post">
      <table>
        <tr>
          <td><label>UserName</label></td>
          <td><input type="text" name="login" /></td>
        </tr>
        <tr>
          <td><label>Password</label></td>
          <td><input type="password" name="password" /></td>
        </tr>
      </table>
      <input type="submit" name="" />
    </form>
  </body>
</html>

 

 

메인 페이지 main.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 method="POST">
      <h1>메인페이지</h1>
      <button name="loginpage" value="login-page">로그인페이지</button>
      <button name="naver" value="naver-page">검색페이지</button>
    </form>
  </body>
</html>

 

 

app.js

const express = require("express");
const cookieParser = require("cookie-parser");
const bodyParser = require("body-parser");
const morgan = require("morgan");
const fs = require("fs");
const app = express();
const port = 3001;

//미들 웨어 설정
app.use(morgan("dev"));
app.use(cookieParser());
app.use(bodyParser.urlencoded({ extended: false }));

//라우터 설정
// app.get("/", (req, res) => res.send("Hello World"));
//들어가서 뜨는 로그인페이지 만약 쿠키들어있으면 성공 뜸
// app.get("/", (req, res) => {
//   if (req.cookies.auth) {
//     res.send("<h1>Login Success</h1>");
//   } else {
//     res.redirect("/login");
//   }
// });
// //메인페이지 추가해봄
app.get("/", (req, res) => {
  if (req.cookies.auth) {
    res.send("<h1>Login Success</h1>");
  }

  // fs.readFile("main.html", (error, data) => {
  //   res.send(data.toString());
  // });
  else {
    // res.redirect("/login");

    //send는 한번만 쓸수 있어서..end처럼끝내버리는거였음 그래서 밑에또부를때충돌남!!
    //여러개쓰고 싶으면 write
    //그거뿐만 아니라 불러올때 충돌나는것도 있음..
    fs.readFile("main.html", (error, data) => {
      res.send(data.toString());
    });
  }
});

app.post("/", (req, res) => {
  if (req.body.loginpage) {
    console.log(req.body);
    res.redirect("/login");
  } else req.body.naver;
  {
    res.redirect("https://www.naver.com/");
  }
});

//html페이지로
app.get("/login", (req, res) => {
  fs.readFile("login.html", (error, data) => {
    res.send(data.toString());
  });
});
//단순페이지요청(클라이언트가ㅏ요청한걸로 쿠키생성)
app.post("/login", (req, res) => {
  //쿠키생성
  let login = req.body.login;
  let password = req.body.password;
  console.log(login, password);
  console.log(req.body);
  if (login == "rint" && password == "1234") {
    res.cookie("auth", true);
    res.redirect("/");
  } else {
    res.redirect("/login");
  }
});

app.listen(port, () => console.log("example app listening on port"));

 

 

 

콘솔에서

cd 폴더주소

npm start

 

하면 

콘솔 넣은거 example app listening on port 잘 뜸

 

port 값 3001로 할당해놔서 들어가면

뜬다! 

 

버튼 두개 만들어놓은 이유가 button 눌렀을 때 name 값 잘 보내와지는지 볼라고

메인페이지 일때 

 

만약

localhost:3001/ 일때

요청.바디에 name=loginpage 이면

응답. 다시지시. localhost:3001/login

 

그것도 아니면 

요청.바디에.naver이면

응답. 다시지시.링크

 

 

로그인 페이지 넘어오면 

 

내가 get post 차이가 뭘까 에러날때마다 

다같이 얘기했음 이것도 찾아서 정리해봐야겠다

 

암튼 내가 이해한거는  

/login 일때

fs.readFile 이거는 파일 읽어서 불러오고 띄우고 

응답으로 res.send (express에서는 이거 사용)

 

 

요청.바디에.login을 login에 할당

할당하고

만약 input의 name=login이랑 정한 값이랑 같으면

응답.특정 쿠키를 만들어서

응답. "/"로 다시 불러와

 

그거 아니면

응답."/login" 불러와

 

 

 

설정한 값 잘 넣어서

쿠키값이 가지고 응답되었어!

그래서 "/" 다시 메인페이지로 돌아왔는데

왜 글자가 뜨냐면

 

 

 

 

 

 

 

만약에 

요청.쿠키들이.auth 면

응답.글자로~

 

이거 넣어서 임.

 

사실 처음에 잘되다가 

[nodemon] app crashed - waiting for file changes before starting...

 

다시 메인페이지, 버튼 두개 있는 창 띄우고 싶어서쿠키값을 오른쪽에서 삭제했는데에러가 막뜨는거야 

 

 

컨트롤 C해서

npm start

 

다시 구동했는데 됐다가 안됐다가...에러 자꾸 뜸

 

 

 

redirect를 많이해서 그런가 했는데 

위에 코드에도 적었지만

 

 

res.send 때문이었음

이게 응답과 동시에 끝내줘서 다음 동작에 안넘어가는 거야

 

그리고 원래 

 

  fs.readFile("main.html", (errordata=> {

      res.send(data.toString());

    });

 

이게 else안에 있는게 아니라 "/" 일때 맨 위에 있었고 그다음에 if였음

 

메인페이지 띄우라는 거랑

쿠키값 있을때 h1 글자창 띄우라는 거랑 충돌 났나봐

 

그래서 else 안에 넣어준거임

res.send도 하나만 쓸 수 있어서 if else 안에 넣어주고...

 

 

 

app.get

app.post 차이

 

 

res.send res.write 차이 궁금~

728x90
728x90

책 Node.js 교과서 개정2판 조현영 지음

const express = require("express");
//express모듈을 app변수에 할당
const app = express();
//app.set("port", 포트);로 서버가 실행될 포트를 설정
//process.env 객체에 PORT속성이 있으면 그값을 쓰고 아니면 3000
//app.set(키,값)
app.set("port", process.env.PORT || 3000);
//app.get(주소,라우터)는 주소에 대한 get요청 올때 어떤 동작할지 적는부분
//현재GET /요청시 응답으로 Hello,Express를 전송.
//익스프레스에서는 res.write나 res.end대신 res.send를 사용하면 됨
app.get("/", (req, res) => {
  res.send("Hello,Express");
});
//(GET요청 외에도 POST,PUT,PATCH,DELETE,OPTIONS에 대한 라우터를 위한 app.post,app.put~~메서드가 존재한다)
//listen은 http웹서버와 동일.포트연결하고 서버실행. 포트는 app.get('port')로 가져옴
app.listen(app.get("port"), () => {
  console.log(app.get("port"), "번 포트에서 대기 중");
});

///단순 문자열 대신 HTML로 응답하고 싶다면 res.sendFile메서드 사용하면 됨
파일의 경로를 path모듈을 사용해서 지정해야함
const express = require("express");
const path = require("path");
const app = express();
app.set("port", process.env.PORT || 3000);

app.get("/", (req, res) => {
  //res.send('Hello,Express');
  res.sendFile(path.join(__dirname, "/index.html"));
});

app.listen(app.get("port"), () => {
  console.log(app.get("port"), "번 포트에서 대기 중");
});

 

 

 

미들웨어도 해보기

////6.2 자주 사용하는 미들middle웨어
//미들웨어는 익스프레스의 핵심
//요청과 응답의 중간(미들middle)에 위치하여 미들웨어라 부름
//라우터와 에러 핸들러 또한 미들웨어의 일종
//미들웨어는 요청과 응답을 조작하여 기능을 추가하긷 하고 나쁜 요청을 걸러내기도함
//미들웨어는 app.use와함께 사용. >>>app.use(미들웨어)<<

//익스프레스 서버에 미들웨어를 연결해보자
const express = require("express");
//
const morgan = require("morgan");
const cookieParser = require("cookie-parser");
const session = require("express-session");
const dotenv = require("dotenv");
const path = require("path");
//
dotenv.config();
const app = express();
app.set("port", process.env.PORT || 3000);
//app.use에 매개변수가 req,res,next인 함수를 넣으면 됨
//미들웨어는 위에서 아래로 순서대로 실행되고 요청과 응답사이에 특별한 기능추가할수있음
//next라는 세번째 매개변수를 사용했는데 다음 미들웨어로 넘어가는 함수임
app.use(morgan("dev"));
app.use("/", express.static(path.join(__dirname, "public")));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser(process.env.COOKIE_SECRET));
app.use(
  session({
    resave: false,
    saveUninitialized: false,
    secret: process.env.COOKIE_SECRET,
    cookie: {
      httpOnly: true,
      secure: false,
    },
    name: "session-cookie",
  })
);

//

app.use((req, res, next) => {
  console.log("모든 요청에 다 실행됩니다.");
  next();
});
//현재app.get 라우터에 미들워에 두개 연결되어있음 이때도 next호출해야 다음 미들웨어로 넘어감
app.get(
  "/",
  (req, res, next) => {
    console.log("GET / 요청에서만 실행됩니다.");
    next();
  },
  (req, res) => {
    throw new Error("에러는 에러 처리 미들웨어로 갑니다.");
  }
);
//에러처리미들웨어는 매개변수가 err, req, res, next로 네개야
app.use((err, req, res, next) => {
  console.error(err);
  res.status(500).send(err.message);
});

app.listen(app.get("port"), () => {
  console.log(app.get("port"), "번 포트에서 대기 중");
});

(솔직히 아직 이해는 잘 안되는데 설명 적어놓기)

 

dotenv 패캐지는 .env 파일을 읽어서 process.env로 만든다.

dotenv 패키지의 이름이 dot(점)+env인 이유다. process.env.COOKIE_SECRET에 cookiesecret 값이 할당된다.

키=값  형식으로 추가하면 된다. process.env를 별도의 파일로 관리하는 이유는 보안과 설정의 편의성 때문.

비밀 키들을 소스 코드에 그대로 적어두면 소스코드 유출 시 키도 유출됨. 따라서  .env 같은 별도의 파일에 비밀 키를 적어두고 dotenv 패키지로 비밀키를 로딩하는 방식으로 관리하곤함. .env 파일만 잘 관리하면 비밀키 지킬 수 있다.

 

 

터미널 이렇게 잘 뜸

(책에서 콘솔 이라는데 )

 

얘는 morgan 미들웨어에서 나오는 것. 

[HTTP 메서드] [주소] [HTTP 상태코드] [응답속도]-[응답 바이트]

 

를 의미함. 요청과 응답 한눈에 볼 수 있음

 

 

 

 

 

 

morgan 미들웨어 다음과같이 사용

app.use(morgan("dev"));

dev 이외에 combined, common, short, tiny 등을 넣을 수 있음 

인수 바꾸면 로그 달라져~

 

 

static 미들웨어

정적인 파일들을 제공하는 라우터(클라이언트의 요청 경로(path)를 보고 이 요청을 처리할 수 있는 곳으로 기능을 전달해주는) 역할을 함.

다음과 같이 사용

app.use("요청경로"express.static("실제경로"));

우리가 쓴거~

app.use("/"express.static(path.join(__dirname"public")));

 

함수의 니수로 정적 파일들이 담겨있는 폴더를 지정하면 된다. p237 이해안되면 책봐 미래의 나. 

예로

특정폴더명/stylesheets/style.css 는

http://localhost:3000/stylesheets/style.css  로 접근할 수 있음

css, js,이미지 파일들을  특정폴더에 넣으면 브라우저에서 접근할 수 있게 됨~

 

서버의 폴더 경로와 요청 경로가 달라서 외부인이 서버구조 쉽게 파악할 수 없어 보안에 좋아~

 

정적 파일들을 알아서 제공해줘서 4.3절(p190쿠키와 세션이해하기)처럼 fs.readFile로 파일 직접 읽어서 전송할 

필요 없음. 만약 요청 경로에 해당하는 파일이 없으면 알아서 내부적으로 next 포출함.

만약 파일을 발견했다면 다음 미들웨어는 실행되지 않음. 응답으로 파일 보내고 next를 호출하지 않으니까.

 

 

body-parser

요청의 본문에 있는 데이터를 해석해서 req.body객체로 만들어주는 미들웨어.

보통 폼 데이터나 AJAX 요청의 데이터를 처리함

단 멀티파트(이미지,동영상,파일) 데이터는 처리하지 못해서 뒤에 나오는 multer 모듈 사용하면 됨

 

 

body-parser 미들웨어 이렇게 씀

app.use(express.json());

app.use(express.urlencoded({ extended: false }));

 

body-parser는 JSON과 URL-encoded 형식의 데이터 외에도

Raw(요청의 본문이 버퍼 데이터일때 해석하는 미들웨어),

Text(덱스트 데이터 일때 해석하는 미들웨어)

형식의 데이터를 추가로 해석할 수 있음

 

 

 

npm i body-parser

 

이거 적어서 깔고 아래꺼 추가함

//body-parser
const bodyParser = require("body-parser");
app.use(bodyParser.raw());
app.use(bodyParser.text());

JSON은 JSON 형식의 데이터 전달 방식이고 URL-encoded 는 주소형식으로 데이터를 보내는 방식.

폼 전송은 주로 후자 사용함. 

urlencoded 메서드 보면 { extended: false } 라는 옵션이 들어있음 

이 옵션이 false면  노드의 querystring 모듈을 사용해 쿼리 스트링을 해석하고 true면 qs 모듈을 사용해서 쿼리스트링을 해석한다........

4.2절에서 POST와 PUT 요청의 본문 전달 받으려면 req.on('data') 와  res.on('end') 로 스트림 사용해야 했지

하지만 body-parser을 사용하면 그럴 필요없어 내부적으로 스트림을 처리해 req.body에 추가한다. 

 

 

cookie-parser

요청에 동봉된 쿠키를 해석해 req.cookies 객체로 만든다.

 

사용하는 법

app.use(cookieParser(비밀키)); 

해석된 쿠키들은 req.cookies 객체에 들어감예로 name=zerocho 쿠키를 보내면req.cookies는 {name:zerocho} 가 됨. 유효기간이 지난 쿠키는 알아서 걸러짐

 

쿠키는 클라이언트에서 위조하기 쉬워서 비밀키를 통해 만들어낸 서명을 쿠키 값 뒤에 붙임.서명 붙으면 쿠키가 name=zerocho.sign 과 같은 모양됨~서명된 쿠키는 req.cookies 대신 req.signedCookies 객체에 들어있음

 

 

cookie-parser가 쿠키 생성할 때 쓰이는 것은 아님!

 

쿠키 생성/제거 할때는 

res.cookie(키, 값, 옵션)

res.clearCookie 

메서드 사용해야함

 

옵션은 domain, expires,httpOnly,maxAge,path,secure 등있음

 

이렇게~

res.cookie("name""zerocho", {

  expires: new Date(Date.now() + 900000),

  httpOnly: true,

  secure: true,

});

res.clearCookie("name""zerocho", { httpOnly: truesecure: true });

 

쿠키를 지우려면 키와 값, 옵션도 정확히 일치해야 지워짐

단 expires 나 maxAge옵션은 일치할 필요 없어

 

signed 옵션은 true로 설정하면 쿠키 뒤에 서명이 붙음

서명을 위한 비밀 키는 cookieParser 미들웨어에 인수로 넣은 process.env.COOKIE_SECRET가 됨

 

 

 

express-session

세션 관리용 미들웨어

 

로그인 등 세션 구현하거나 특정 사용자 위한 데이터를 임시저장해둘 때 유용

세션은 사용자 별로 req.session 객체 안에 유지된다. 

app.use( session({

    resave: false,

    saveUninitialized: false,

    secret: process.env.COOKIE_SECRET,

    cookie: {

      httpOnly: true,

      secure: false,

    },

    name: "session-cookie",

  })

);

 

express-session 은 인수로 세션에 대한 설정을 받는다. 

resave는 요청이 올 때 세션에 수정 사항 생기지 않아도 세션을 다시 저장할지 설정하는 것

saveUninitialized 세션에 저장할 내역이 없더라도 처음부터 세션을 생성할지 설정하는 것

둘다 필요없어서 false로 한거야~

 

express-session은 세션 관리시 클라이언트에 쿠키를 보냄 

4.3절에서 배운 세션 쿠키가 이거다 이말임   p240 여기서 보충설명 다시 읽어봐라..

 

 

 

미들웨어의 특성 활용하기

app.use((req,res,next)=>{

    console.log('모든 요청에 다 실행됩니다.');

    next();

})

 

미들웨어는 req,res,next를 매개변수로 가지는 함수로서 

app.use

app.get

app.post

등으로 장착함 

 

특정한 주소의 요청에만 미들웨어가 실행되게 하려면 첫 번째 인수로 주소를 넣으면 된다~

app.use(

  morgan("dev"),

  express.static("/"path.join(__dirname"public")),

  express.json(),

  express.urlencoded({ extended: false }),

  cookieParser(process.env.COOKIE_SECRET)

);

 

 

위처럼 동시에 여러 개의 미들웨어를 장착할 수도 있고 다음 미들웨어로 넘어가려면 next함수 호출해야함.

위 미들웨어들은 내부적으로 next 호출하고 있어서 연달아 쓸 수 있는거.

next 호출하지 않는 미들웨어는 res.send나 res.sendFile 등의 메서드로 응답 보내야함 

express.static과 같은 미들웨어는 정적파일을 제공할때 next 대신  res.sendFile 메서도로 응답보낸다. 

따라서 정적파일 제공하는 경우 

express.json, express.urlencoded,cookieParser 미들웨어는 실행되지 않음

미들웨어 장착 순서에 따라 어떤 미들웨어는 실행되지 않을 수도 ㅇㅆ다느넉ㄹ 기억햊도오아

만약 next 도 호출하지 않고 응답도 보내지 않으면 클라이언트는 응답못받고 계속 기다리게 됨

 

app.use((reqresnext=> {

    req.data = '데이터 넣기';

    next();

  },(req,res,next)=>{

    console.log(req.data);//데이터 받기

    next();

  });

 

현재 요청이 처리되는 동안 req.data를 통해 미들웨어 간 데이터 공유할 수 있음

새로운 요청오면 req.data초기화됨 속성명이 꼭 data일 필요없지만 다른 미들웨어와 겹치지 않고 조심

app.set과의 차이 p244

app.set으로 익스프레스에서 데이터를 저장할 수 있다는 것을 배웠음 app.get 또는 req.app.get으로 어디서든지 데이터를 가져올 수 있음 하지만 app.set 사용안하고 req 객체에 데이터를 넣어서 다음 미들웨어로 전달해야하는 이유가 있다. app.set은 익스프레스에서 전역적으로 사용되므로 사용자 개개인의 값을 넣기에는 부적절하며 앱전체의 설정을 공유할 때 사용하면 됨 
req객체는 요청을 보낸 사용자 개개인에게 귀속되므로 req객체를 통해 개인의 데이터를 전달하는 것이 좋다

 

 

multer

멀티파트 형식으로 업로드할 때 사용하는 미들웨어

 

 

 

 

 

 

https://expressjs.com/ko/guide/routing.html

 

Express 라우팅

라우팅 라우팅은 애플리케이션 엔드 포인트(URI)의 정의, 그리고 URI가 클라이언트 요청에 응답하는 방식을 말합니다. 라우팅에 대한 소개는 기본 라우팅을 참조하십시오. 다음 코드는 매우 기본

expressjs.com

 

728x90
728x90

템플릿 엔진 Template Engine

템플릿 양식과 특정 데이터 모델에 따른 입력 자료를 합성하여 결과 문서를 출력하는 소프트웨어(또는 소프트웨어 컴포넌트)를 말한다


* Template : 공통적인 프레임을 미리 제작한 것

*웹 템플릿 엔진(Web Template Enging)이란? 웹 문서가 출력되는 템플릿 엔진을 말합니다. 즉, 웹 템플릿 엔진은  웹 템플릿들(Web Templates)과 웹 컨텐츠 정보(Content Information)를 처리하기 위해 설계된 소프트웨어입니다.

또한 웹 템플릿 엔진은 View Code(Html)와 Data Logic Code(Db Connection)를 분리해주는 기능을 합니다.

 

오 이사람 설명 잘한다 

https://show-me-the-money.tistory.com/56

 

템플릿 엔진이란 무엇인가?

자, 여기 인형을 만드는 업자가 있습니다. 이 업자는 인형을 만들기 시작한지 얼마 되지 않아 바느질에 익숙하지 않습니다. 고객으로부터 원하는 인형을 주문 받으면 업자는 창고에서 몸통, 눈,

show-me-the-money.tistory.com

 

 

 

출처

 

웹기술 - 템플릿 엔진, template engine 이란 무엇인가

서버 데이터를 정적 파일에 간단히 넘겨주는 기능 template engine 템플릿 엔진(template engine) 은 앱에...

blog.naver.com

 

[Template Engine] 템플릿 엔진(Template Engine)이란 - Heee's Development Blog

Step by step goes a long way.

gmlwjd9405.github.io

 

템플릿 엔진(Template Engine) 이란?

템플릿 엔진이란 템플릿 양식과 특정 데이터 모델에 따른 입력 자료를 합성하여 결과 문서를 출력하는 소프트웨어(또는 소프트웨어 컴포넌트)를 말합니다. * Template : 공통적인 프레임을 미리 제

usefultoknow.tistory.com

 

728x90
728x90

HTTP(Hyper Text Transfer Protocol)

웹 상에서 클라이언트와 서버가 서로 정보를 주고받을 수 있도록 하는 규약

우선 클라이언트는 서버에 정보(데이터) 전송을 요청(Request)할 수 있는 클라이언트 소프트웨어(크롬, IE, 사파리 등 웹 브라우저가 대표적)가 설치된 컴퓨터를 의미한다. 클라이언트는 URL(Uniform Resource Locator)로 된 HTTP를 통해 서버에게 정보 송신을 요청합니다. 우리가 평소 쓰는 URL 구조를 구분해 살피면 각각은 아래와 같은 의미를 가짐.

 

URL의 예: http://www.wishket.com/company-intro
1. http://: 자원에 접근하기 위한 http 프로토콜
2. www.wishket.com: 서버의 위치
3. company-intro: 서버에서 컴퓨터가 요청한 자원의 위치 

 

클라이언트가 이렇게 정보 송신을 요청하면 서버는 대응한다. 서버는 응답하는(Response) 소프트웨어(아파치, nginx, IIS 등)가 설치된 컴퓨터를 의미한다. 서버는 클라이언트의 요청을 해석하고 클라이언트의 요청 및 서버 관리자가 설정한 알고리즘에 준하는 정보를 클라이언트에게 송신한다.

 

 

 

위의 내용을 정리하면 HTTP를 통해 이런 일이 이루어짐~

1. 클라이언트가 보고 싶은 정보를 서버에게 HTTP를 통해 요청.
2. 서버는 알맞은 응답 메시지 및 정보를 클라이언트에게 전달.
3. 응답 메시지 및 정보 중 HTTP바디 내용이 클라이언트가 설정한 클라이언트의 용처에 도달한다.

 

 

 

HTTP의 구조

HTTP는 애플리케이션 레벨의 프로토콜로 TCP/IP 위에서 작동한다. HTTP는 상태를 가지고 있지 않는 Stateless 프로토콜이며 Method, Path, Version, Headers, Body 등으로 구성된다.


하지만 HTTP는 암호화가 되지 않은 평문 데이터를 전송하는 프로토콜이라서 보안 취약

이 문제 해결하기 위해 HTTPS가 등장

 

HTTPS

HyperText Transfer Protocol over Secure Socket Layer, HTTP over TLS, HTTP over SSL, HTTP Secure 등으로 불리는 HTTPS는 HTTP에 데이터 암호화가 추가된 프로토콜이다. HTTPS는 HTTP와 다르게 443번 포트를 사용하며, 네트워크 상에서 중간에 제3자가 정보를 볼 수 없도록 공개키 암호화를 지원하고 있다.

 

‘HTTP vs HTTPS 차이’

 

바로 SSL(보안 소켓 계층) 인증서

 

사실 HTTPS는 쉽게 말해서 HTTP 프로토콜에 보안 기능을 추가한 것

 

SSL 인증서는 사용자가 사이트에 제공하는 정보를 암호화하는데, 쉽게 말해서 데이터를 암호로 바꾼다고 생각하면 쉽다. 이렇게 전송된 데이터는 중간에서 누군가 훔쳐 낸다고 하더라도 데이터가 암호화되어있기 때문에 해독할 수 없다. 그 외에도 HTTPS는 TLS(전송 계층 보안) 프로토콜을 통해서도 보안을 유지. TSL은 데이터 무결성을 제공하기 때문에 데이터가 전송 중에 수정되거나 손상되는 것을 방지하고, 사용자가 자신이 의도하는 웹사이트와 통신하고 있음을 입증하는 인증 기능도 제공하고 있습니다

 

 

사실 HTTPS로 전환하게 되면 검색엔진 최적화(SEO)에 있어서도 큰 혜택을 볼 수 있음

또한 가속화된 모바일 페이지(AMP, Accelerated Mobile Pages)를 만들고 싶을 때도 HTTPS 프로토콜을 사용해만 함 

 

 

 

출처

 

 

728x90
728x90

클라이언트가 보내는 요청의 단점, 누가 보낸 건지 몰라. 

대신 로그인 구현하면 되는데 로그인 한후에 새로고침해도 로그아웃 안되도록 

클라이언트가 서버에 누구인지 지속적으로 알려줘야함

쿠키

클라이언트 로컬에 저장되는

유효기간 있고 name=zerocho 처럼 단순한 Key-Value쌍의 작은 데이터 파일

 

쿠키의 구성요소

1. 이름 : 각각의 쿠키를 구별하는데 사용함

2. 유효시간: 쿠키의 유지시간

3. 도메인: 쿠키를 전송할 도메인

4. 경로: 쿠키를 전송할 요청 경로

5. 값: 쿠키와 이름과 관련된 값

 

 

 

동작방식

1. 클라이언트 -> 페이지 request 요청

2. 서버에서 쿠키를 생성

3. http헤더에 쿠키를 포함해서 respond 응답

4. 브라우저가 종료되어도 쿠키의 기한이 정해져 있지 않고 명시적으로 지우지 않는다면 반 영구적으로 쿠키가 남아있게됨

클라이언트 요청(쿠키가지지 않은 상태)
------------->
쿠키와 함께 응답
<-------------
쿠키와 함께 요청
--------------->
응답(쿠키 가진 상태)
<---------------
서버

 

 

 

세션 

브라우저가 종료되기 전까지 클라이언트의 요청을 유지하게 해주는 기술

 

세션은 어쨌든 쿠키를 기반으로 하고 있음

서버측에서 관리하긴함

 

 

 

사용자 많아질수록 서버 메모리 많이 먹어

클라이언트한테 아이디부여하는데 그게 세션아이디임

 

동작방식

  1. 클라이언트가 서버에 로그인 요청
  2. 서버는 클라이언트의 로그인 요청의 유효성을 확인하고(아이디와 비밀번호 검사) unique한 id를 sessionid라는 이름으로 저장
  3. 서버가 응답할 때 응답헤더에 set-cookie: sessionid:a1x2fjz를 추가하여 응답

   4 . 클라이언트는 이후 서버에 요청할 때 전달받은 sessionid:a1x2fjz쿠키를 자동으로 요청헤더에 추가하여 요청

   5. 서버에서는 요청헤더의 sessionid 값을 저장된 세션저장소에서 찾아보고 유효한지 확인후 요청을 처리하고 응답

 

세션의 내용은 서버에 저장되기 때문에 계속하여 늘어날 경우 서버에 부하가 발생

 

 

쿠키와 세션의 차이점

가장 큰 차이점 정보가 저장되는 위치

 

저장위치

쿠키는 서버에 저장되지 않고 클라이언트 로컬에 저장됨

세션은 서버의 자원을 써서 로컬과 서버에 저장됨

 

장단점

보안면에서는 세션이 좋고

속도면에서는 쿠키가 빠름

 

세션은 쿠키를 이용해 id만 저장하고 서버에 저장해

세션도 만료시간 정할 수 있지만 브라우저가 종료되면 만료시간 상관없이 날라감

쿠키는 브라우저 종료해도 파일로 남아있음

 

 

 

얘를 보완해서 JWT가 나옴 책에도 나와~

 

 

 

 

 

책보면서 직접 코드 따라해보기

 

cookie.js  

const http = require("http");
http
  .createServer((req, res) => {
    console.log(req.url, req.headers.cookie);
    res.writeHead(200, { "Set-Cookie": "mycookie=test" });
    res.end("Hello Cookie");
  })
  .listen(8083, () => {
    console.log("8083번 포트에서 서버 대기 중입니다");
  });

 

터미널

 경로 입력하고 서버대기 중 확인

 

 

createServer 메서드의 콜백에서는 req 객체에 담겨있는 쿠키 가져옴

쿠키는

req.headers.cookie 에 들어있음

req.headers는 요청의 헤더 의미 (쿠키는 요청과 응답의 헤더를 통해 오감)

응답의 헤더에 쿠키를 기록해야 돼서

res.writeHead 메서드를 사용함 

"Set-Cookie": "mycookie=test" 는 "다음에 오는 쿠키를 저장해라 : 다음"

 

 

 

 

로컬주소에 접속

req.url과 req.headers.cookies에 대한 정보를 로깅하도록 함

req.url은 주소의 path와 search부분을 알림 (사실 이부분 이해안돼서 찾아봤는데 이해안됨 그래도 읽어보자)

아 이건인가봐 (뒤늦게 발견)

 

 

 

 

위 코드까지는 쿠키 심기만 한거고

그 쿠키가 나인지를 식별 못하고 있음

이제는 사용자를 식별하는 방법을 알아보자

 

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>

cookie2.js

const http = require("http");
const fs = require("fs").promises;
const url = require("url");
const qs = require("querystring");
//쿠키는 문자열임 이를 쉽게 사용하기 위해 js객체 형식으로 바꾸는  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으로 시작하는 경우,url과 querystring모듈로 각각 주소와 주소에 딸려오는 query분석한다
    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);
      //헤더에 302응답코드,리다이렉트 주소와 함께 쿠키를 넣어
      //브라우저는 이 응답코드를 보고 페이지를 해당주소로 리다이렉트함
      //헤더는 한글을 설정할 수 없어서 name변수를encodeURIComponent메서드로 인코딩함
      res.writeHead(302, {
        Location: "/",
        "Set-Cookie": `name=${encodeURIComponent(
          name
        )}; Expires=${expires.toGMTString()};HttpOnly;path=/`,
      });
      res.end();

      //그 외의 경우(/로 접속했을때 등),먼저 쿠키있나없나확인. 없으면 로그인할 수 있는페이지보냄
      //처음 방문한경우 쿠키없으므로 cookie2.html 전송됨 쿠키있다면 로그인한상태로 간주해인사말보냄
      //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번 포트에서 서버 대기중입니다!");
  });

set-Cookie로 쿠키 설정할 때 

만료시간 expires 과 HttpOnly, Path같은 옵션 부여함

쿠키 설정할 때 각종 옵션 넣을 수 있고 옵션 사이 세미콜론(;) 써서 구분

쿠키에는 한글 쓰기, 줄바꿈 하면 안됨

  • 쿠키명=쿠키값  기본적 쿠키값 예) mycookie=test
  • Expires=날짜: 만료기한. 기본값은 클라이언트가 종료될 때까지
  • Domain= 도메인명:  쿠키가 전송될 도메인 특정할 수 있음. 기본값은 현재 도메인
  • Path=url : 쿠키가 전송될 url을 특정할 수 있음 기본값은'/'이고 이경우 모든 url에서 쿠키 전송할 수 있음
  • secure: HTTPS 일 경우에만 쿠키가 전송됨
  • HttpOnly: 설정 시 자바스크립트에서 쿠키에 접근할 수 없음 쿠키 조작을 방지하기 위해 설정하는 것이 좋음

 

 

 

 

 

이제 이름 노출안되는 버전

세션 방식.

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

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();
      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번 포트에서 서버 대기 중입니다");
  });

 

코드 따라썼는데 자꾸 안된다고 에러뜸 

바로 이 에러~!!

NodeJS address already in use 

찾아서 따라해서 이전 포트? 종료하고 다시 함

로컬주소 들어가서 정보 입력하니까!

 

 아까 넣었던 쿠키 위에 쌓였다.

이 방식이 세션임

 

 

아까랑 다른 건 쿠키에 이름을 담아서 보내는 대신, uniqueInt라는 숫자값을 보냄. 사용자의 이름과 만료시간은 uniqueInt 속성명 아래에 있는 session이라는 객체에 대신 저장함

이제 cookie.session이 있고 만료기한 넘기지 않았으면 session 변수에서 사용자 정보를 가져와 사용한다.

 

 

안전하게 사용하기 위해서는 다른 사람들이 만든 검증된 코드를 사용하는게 좋대

그건 책 5장에서~~~

 

 

 

 

 

 

 

 

그.런.데.

내가 코드를 다 이해했다? 전혀 아니지요.

 

map 메서드

배열.map((요소, 인덱스, 배열) => { return 요소 });

const oneTwoThree = [1, 2, 3];
let result = oneTwoThree.map((v) => {
  console.log(v);
  return v;
});
// 콘솔에는 1, 2, 3이 찍힘
oneTwoThree; // [1, 2, 3]
result; // [1, 2, 3]
oneTwoThree === result; // false

reduce 메서드

배열.reduce((누적값, 현잿값, 인덱스, 요소) => { return 결과 }, 초깃값);

result = oneTwoThree.reduce((acc, cur, i) => {
  console.log(acc, cur, i);
  return acc + cur;
}, 0);
// 0 1 0
// 1 2 1
// 3 3 2
result; // 6

acc(누적값)이 초깃값인 0부터 시작해서 return하는대로 누적되는 것을 볼 수 있습니다. 초깃값을 적어주지 않으면 자동으로 초깃값이 0번째 인덱스의 값이 됩니다.

 

그렇다고 함 이것이 바로 설명 링크.. 읽어도 잘모르겠지만 암튼 보자 

 

 

 

 

 

 

 

NodeJS address already in use 문제 해결 - JooTC

NodeJS address already in use 문제 해결 방법 Error: listen EADDRINUSE: address already in use :::5000 현재 다른 프로세스에서 사용 중이라 해당 서비스를 시작할 수 없다는 에러입니다.

jootc.com

 

 

 

 

 

출처

728x90
728x90

개념 정리 <Node.js교과서>- 조현영 지음 책 요약

 

Node.js®는 Chrome V8 JavaScript 엔진으로 빌드된 JavaScript 런타임입니다.

 

 

기본개념

 

1.서버

네트워크를 통해 클라이언트레 정보나 서비스를 제공하는 컴퓨터 또는 프로그램

 

노드는 서버 애플리케이션 실행하는데 제일 많이 사용됨.

서버는 클라이언트의 요청에 대해 응답해야 함. 

 

 

2. 자바스크립트 런타임

노드는 자바스크립트 런타임. 런타임은 특정 언어로 만든 프로그램들을 실행할 수 있는 환경을 뜻함

 

 

<노드의 내부 구조>

Node.js Core Library
Node.js Bindings
V8 (  -> 오픈소스 자바스크립트 엔진) libuv (  -> 비동기 I/O)

 

3. 이벤트 기반 event-driven

이벤트(클릭, 네트워크 요청 등과 같은)가 발생할 때 미리 지정해둔 작업을 수행하는 방식 의미한다.

특정 이벤트가 발생할 때 무엇을 할지 미리 등록해놔야하는데 이걸 이벤트 리스너에 콜백함수를 등록한다고 표현한다.

발생한 이벤트가 없거나 발생했던 이벤트를 다 처리하면 노드는 다음 이벤트가 발생할 때까지 대기.

 

<이벤트 기반>

시스템 2. 이벤트 발생
--------------------->

<---------------------
3. 등록된 콜백함수 호출
이벤트 리스너

1. 이벤트 리스너에 콜백함수 등록

이벤트 기반 모델에서는 이벤트 루프라는 개념 등장. 여러 이벤트 동시발생시 어떤 순서로 콜백함수를 호출할지를 이벤트 루프가 판단함.  노드와 자바스크립트에서 이벤트 루프는 정말 중요 개념~!

 

이벤트 루프:
이벤트 발생시 호출할 콜백 함수들을 관리하고, 호출된 콜백 함수의 실행순서결정하는 역할 담당. 노드가 종료될 때까지 이벤트 처리위한 작업을 반복해서 루프라고 부름.
백그라운드:
setTimeout 같은 타이머나 이벤트 리스너들이 대기하는 곳. 자바스크립트가 아닌 다른 언어로 작성된 프로그램이라고 봐도 된다. 여러 작업이 동시에 실행될 수 있음
테스크 큐:
이벤트 발생 후, 백그라운드에서는 테스크 큐로 타이머나 이벤트 리스너의 콜백 함수를 보낸다. 정해진 순서대로 콜백들이 줄 서 있어서 콜백 큐라고 부른다. 보통은 완료된 순서대로 서있지만 특정한 경우 순서 바뀌기도함.

 

4. 논 블로킹 I/O 

 

작업은

동시에 실행될 수 있는 작업과

동시에 실행될 수 없는 작업있음 

 

자바스크립트 코드는 동시에 실행될 수 없음

하지만 js상에서 돌아가는게 아닌 입력Input 출력Output 작업같은 건 동시처리 가능

 

(파일 시스템 접근이나 네트워크를 통한 요청 같은 작업이 I/O의 일종)

 

이런 작업시 노드는 

논블로킹 방식으로 처리하는 방법을 제공한다. 

 

<백그라운드 작업완료 확인 여부>
논블로킹:
이전 작업이 완료될 때까지 대기하지 않고 다음작업 수행
블로킹:
이전 작업 끝나야만 다음작업 수행

 

 

노드는 I/O 작업을 백그라운드로 넘겨 동시에 처리하곤 함.

작업 순서에 따라 작업 시간 단축되어 성능 크게 달라짐! 동시에 처리될 수 있는 I/O 작업이라도 논블로킹 방식으로 코딩하지 않으면 의미 퇴색되므로 논 블로킹 방식으로 코딩하는 습관 들이기!!

 

하지만 아무리 논블로킹 방식으로 코드 작성해도 우리가 전부 작성한 코드는 서로 동시에 실행되지 않기에 소요시간이 짧아지진 않는다. 실행 순서만 바뀔뿐. 그래도 논블로킹을 통해 실행 순서를 바꿔줌으로써 그 작업 때무에 간단한 작업들이 대기하는 상황을 막을 수 있다는 점에서 의의가 있다. 

논블로킹과 동시가 같은 의미가 아니라는 것도 알아두기 . 동시성은 동시 처리가 가능한 작업을 논 블로킹 처리해야 얻을 수 있음.

노드에서는 동기와 블로킹이 유사하고 비동기와 논블로킹이 유사함.

<함수가 바로 return되는지 여부>
동기(synchronous : 동시에 일어나는):
블로킹 방식에서는 백그라운드 작업 완료 여부를 계속 확인하며, 호출한 함수가 바로 return되지 않고 백그라운드 작업이 끝나야 return된다. 
비동기(Asynchronous : 동시에 일어나지 않는):
논블로킹 방식에서는 호출한 함수가 바로 return되어 다음 작읍으로 넘어가며, 백그라운드 작업 완료 여부는 신경쓰지 않고 나중에 백그라운드가 알림을 줄 때 비로소 처리함.

 

동기:  요청과 결과가 한 자리에서 동시에 일어남.설계가 매우 간단하고 직관적이지만 과가 주어질 때까지 아무것도 못하고 대기해야 하는 단점이 있고, 

비동기:  요청한 그 자리에서 결과가 주어지지 않음 동기보다 복잡하지만 결과가 주어지는데 시간이 걸리더라도 그 시간 동안 다른 작업을 할 수 있으므로 자원을 효율적으로 사용할 수 있는 장점이 있습니다.
출처: https://private.tistory.com/24 [공부해서 남 주자]

 

 

 

5. 싱글스레드

 

스레드가 하나뿐이라는 것.

 

프로세스:  운영체제에서 할당하는 작업의 단위.

노드나 웹브라우저 같은 프로그램은 개별적인 프로세스임. 프로세스 간에는 메모리등의 자원 공유안해

스레드: 프로세스 내에서 실행되는 흐름의 단위.

프로세스는 스레드를 여러 개 생성해 여러 작업을 동시에 처리할 수 있음. 스레드들은 부모 프로세스의 자원공유해. 같은 주소의 메모리에 접근 가능해 데이터를 공유할 수 있어

 

 

 

노드는 싱글 스레드?

엄밀히 말하면 싱글 스레드로 동작하지 않음

노드를 실행하면 먼저 프로세스 하나 생성됨 그 프로세스 안에서 스레드 여러개 생성함 . 우리가 직접 제어할 수 있는 스레드는 하나뿐! 그래서 흔히 노드가 싱글 스레드라고 여겨짐.

스레드는 작업을 처리하는 일손. 하나의 스레드만 직접 조작할 수 있으니까 일손이 하나인 것임.

블로킹이 발생할 것 같은 경우에는 논블로킹 방법으로 대기시간을 최대한 줄인다. 

 

 

<노드가 싱글 스레드로 동작하지 않는 두 가지 경우>

스레드풀(Thread Pool)

노드가 특정 동작을 수행할 때 스스로 멀티 스레드를 사용한다. 대표적인 예로 암호화(3.5.5절), 파일입출력(3.6절),압축(3.6.2절) 등이 있다

워커 스레드(Worker Thread)

이제 노드에서도 멀티 스레드를 사용할 수 있게한 기능. 우리가 직접 다수의 스레드를 다룰 수 있음. CPU 작업(연산이 많은 작업)이 많은 경우 워커 스레드를 사용하면 된다.

 

 

 

서버로서의 노드

 

노드는 기본적으로 싱글 스레드, 논블로킹 모델을 사용함. 

따라서 노드 서버의 장단점은 싱글 스레드, 논블로킹 모델의 장단점과 비슷함.

 

노드는 CPU부하가 큰 작업에는 적합하지 않음 연산을 많이 요구하면 스레드 하나가 혼자 감당하기 어려워!

노드는 개수는 많지만 크기는 작은 데이터를 실시간으로 주고받는데 적합함.

네트워크나 데이터베이스, 디스크 작업 같은 I/O에 특화되어있음

 

<노드의 장단점>

장점 단점
멀티 스레드 방식에 비해 적은 컴퓨터 자원 사용 기본적으로 싱글 스레드라서 CPU코어를 하나만 사용
I/O 작업이 많은 서버로 적합 CPU작업이 많은 서버로는 부적합
멀티 스레드 방식보다 쉬움 하나뿐인 스레드가 멈추지 않도록 관리가 필요함
웹 서버가 내장되어있음 서버 규모가 커졌을 때 서버를 관리하기 어려움
자바스크립트를 사용함 어중간한 성능
JSON형식과 쉽게 호환됨  

 

 

 

 

 

 

 

728x90

+ Recent posts