고양이와 코딩

[웹 풀사이클 데브코스 TIL] 2주차 Day 4 - 웹 생태계 전반에 대한 실습(1) 본문

데브코스 TIL

[웹 풀사이클 데브코스 TIL] 2주차 Day 4 - 웹 생태계 전반에 대한 실습(1)

ovovvvvv 2023. 11. 23. 23:32
728x90

1. 프로젝트 개요

테니스 라켓을 구매하는 쇼핑몰을 만들어 봅시다

 

페이지 구성

  • mainPage - 상품을 구매할 수 있는 페이지
  • orderPage - 상품 구매 후 안내해주는 페이지
  • order list Page - 구매한 상품의 정보를 확인할 수 있는 페이지

 

2. 메인 페이지

main.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Main</title>
  </head>
  <body>
    <h1>Tennis market</h1>
    <div>
      Welcome to Tennis market!<br />
      Enjoy your shopping.
      <br />
      <br />
      <a>order list</a>
    </div>
    <img src="./img/redRacket.png" />
    <p>Red Racket</p>
    <input type="button" value="order" onclick="alert(1);" />
  </body>
</html>

지난 시간에 배웠던 태그들이 다 들어있습니다!

3개의 테니스 이미지를 넣을건데요 

    <div class="card">
      <img class="card_img" src="./img/redRacket.png" />
      <p class="card_title">Red Racket</p>
      <input
        class="card_button"
        type="button"
        value="order"
        onclick="alert(1);"
      />
    </div>
    <div class="card">
      <img class="card_img" src="./img/blueRacket.png" />
      <p class="card_title">Blue Racket</p>
      <input
        class="card_button"
        type="button"
        value="order"
        onclick="alert(2);"
      />
    </div>
    <div class="card">
      <img class="card_img" src="./img/blackRacket.png" />
      <p class="card_title">Black Racket</p>
      <input
        class="card_button"
        type="button"
        value="order"
        onclick="alert(3);"
      />
    </div>

기존 이미지 + 상품이름 + 버튼 에 해당하는 태그들을 div로 한번에 묶어서 복사 붙여넣기 해줬어요

+ 클래스 이름도 지정해 줬습니다 (css를 위해 ㅎㅎ)

 

 

3. 주문 내역 페이지

이번에는 orderList 파일을 생성 해 봅니다!

여기서 table 태그를 사용할건데요, 

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Order List</title>
  </head>
  <body>
    <h1>Order List</h1>
    <a href="main.html">go home</a>

    <table>
      <th>No</th>
      <th>Product</th>
      <th>Description</th>
      <th>Price</th>
      <th>Order Date</th>
    </table>
  </body>
</html>

이렇게 생성이 됩니닿 (열)

 

그렇다면 tr을 사용하면 어떻게 나올까요 ?

      <tr>
        <td>1</td>
        <td>produce1</td>
        <td>description1</td>
        <td>price1</td>
        <td>date1</td>
      </tr>
      <tr>
        <td>1</td>
        <td>produce1</td>
        <td>description1</td>
        <td>price1</td>
        <td>date1</td>
      </tr>

이렇게 나옵니다 ㅎㅎ

 

현재까지 css까지 간략하게 맥인 화면은 이렇습니다 !

 

 

4. 백엔드의 구조

* 정적 페이지 : 화면의 내용/데이터 등의 변동이 없는 페이지

* 동적 페이지: 데이터 처리/연산을 통해 화면의 내용, 데이터가 변하는 페이지

* 데이터베이스 : 데이터를 통합하여 효율적으로 관리하기 위한 데이터 집합체

 

웹 서버는 정적 페이지에 대해 대응해요. 동적 페이지에 대한 처리는 직접 하지 않고 웹 어플리케이션 서버에게 전달합니다 !

웹 어플리케이션 서버는 동적 페이지를 처리합니다.필요한 연산을 위해 데이터베이스와 연결되어 있고 데이터 조회/수정/삭제에 대한 처리를 요청해요

 

 

5. Node.js 소개 및 설치

Node.js 란?

- 자바스크립트를 스크립트 언어 이상으로 프로그래밍 언어 역할을 할 수 있도록 지원하는 플랫폼

(자바스크립트가 백엔드 세상에서 뛰어놀수 있는 운동장을 제공하는 친구라고 하시네요 ( •͈ᴗ•͈)◞)

 

노드는 안정적인 LTS버전으로 받아 주도록 하겠습니다 !

 

 

6. Node.js로 웹서버 만들기

저번에 만들었던 WebStart 폴더에서 server.js를 생성해 줬어요

let http = require("http");

http.createServer()

createServer() 함수가 서버를 생성해줘요,

 

let http = require("http");

function onRequest(request, response) {
  response.writeHead(200, { "Content-Type": "text/html" });
  response.write("Hello Node.js");
  response.end();
}

http.createServer(onRequest).listen(8888);

createServer()는 Node.js의 http 모듈에 있는 함수 중 하나로, 웹 서버를 생성하는데 사용돼요 !

함수의 인자인 function(request, response)는 콜백 함수로, 요청과 응답을 다루는 로직을 담고 있습니다

 

이제 vscode 터미널에서 명령어를 입력해서 서버를 구동시켜볼게요 

node server.js

서버가 구동됐습니다 😺

 

 

7. HTTP 템플릿

클라이언트와 서버가 통신을 하고 싶다면, 주파수를 맞춰야 합니다 !

 

HTTP 프로토콜 템플릿

 

 

8. server.js 모듈화

사용을 좀 더 용이하게 하기위해 모듈화를 해볼게요

index.js 파일을 만들어서 

let server = require("./server");

입력해 준 뒤

node index.js

명령어로 서버를 구동시킨 뒤 새로고침 해 보면, 직접적으로 node server.js를 입력하지 않아도 잘 나오는걸 볼 수 있어요

 

내가 만든 서버를 모듈처럼!

Node.js가 미리 만들어 둔 모듈을 우리가 require('모듈 이름'); 으로 사용한 것 처럼,

우리가 만든 서버도 모듈처럼 다른 javascript파일에서 사용할 수 있습니다 ㅎㅎ

server.js         <-        index.js

 

그렇다면 서버를 불러와서 실행 시키고 싶을 때 실행하려면 어떻게 해야할까요 ? 

function onRequest(request, response) {
  response.writeHead(200, { "Content-Type": "text/html" });
  response.write("Hello Node.js");
  response.end();
}

http.createServer(onRequest).listen(8888);

서버를 실행시키는 이 부분을 함수로 안에 넣고 서버를 실행시키면 오류가 발생합니다 ❗️

함수를 밖으로 내보내서 사용하고 싶다면 export 시켜주어야 해요

 

let http = require("http");

function start() {
  function onRequest(request, response) {
    response.writeHead(200, { "Content-Type": "text/html" });
    response.write("Hello Node.js");
    response.end();
  }

  http.createServer(onRequest).listen(8888);
}

exports.start = start;

server.js

 

let server = require("./server");

server.start();

index.js

 

이제 node.index.js로 다시 서버를 실행시켜 보면

다시 정상적으로 나옵니다 (๑• ̫•๑)♡

 

 

9. Url 읽어내기

URL(Uniform Resource Locator) : 인터넷 상에서 웹 페이지가 어디에 있는지 '위치'를 알려주는 주소 === 웹 페이지 주소

 

    let pathname = url.parse(request.url).pathname;
    console.log("pathname: " + pathname);

코드를 이렇게 추가하고 서버를 새로고침하면 터미널에

이렇게 현재 url이 찍히는데요, /favicon.ico는 무시하는 코드를 짜면 된다고 하지만 일단은 그냥 진행 해 보도록 할게요 ㅎㅎ

 

route.js 파일을 만들고 

function route(pathname) {
  console.log("pathname: " + pathname);
}

exports.route = route;

 

server.js에서 

let http = require("http");
let url = require("url");

function start(route) {
  function onRequest(request, response) {
    let pathname = url.parse(request.url).pathname;
    route(pathname);

    response.writeHead(200, { "Content-Type": "text/html" });
    response.write("Hello Node.js");
    response.end();
  }

  http.createServer(onRequest).listen(8888);
}

exports.start = start;

route에게 pathname을 전달 해 줍니다. (start 함수 내에 인자로 route를 받는것도요 !!)

그치만 서버에서 route를 어떻게 알 수 있을까요 .. 🧐

 

server.js에서 start() 함수를 호출해주는 index.js파일에서 작업 할 수 있습니다 !

let server = require("./server");
let router = require("./router");

server.start(router.route);

index.js 파일

 

그리고 다시 서버를 실행 시켜 보아요

 

** 하나의 파일에서도 서버가 구동되는데 왜 이렇게 따로따로 작업하는거지? 하는 의문이 들었지만,

역할을 분리시킨 것 뿐이라고 하시니까 바로 이해가 됐습니다...파일에서 함수를 따라따라 가보니 쉽게 알 수 있는 것 같아요 ㅎㅎ

 

 

10. URL에 따라 다른 콘솔 찍기 (백엔드만)

송아쌤이 정리해준 ㅎ ㅎ

저번 시간까지는 Route에서 할 일은 정해주지 않았어요 !

이번 시간에 배워보려고 합니다 ~

 

requestHandler.js 파일을 만들어서

function main() {
  console.log("main");
}

function login() {
  console.log("login");
}

let handle = {}; // key:value 쌍으로 이루어진 변수 상자

handle["/"] = main;
handle["/login"] = login;

exports.handle = handle;

이렇게 코드를 작성해줍니다

그리고 저번에도 그랬듯 index.js 파일에서 불러와 보도록 할게요

 

let server = require("./server");
let router = require("./router");
let requestHandler = require("./requestHandler");

server.start(router.route, requestHandler.handle);

 == start라는 함수가 handle 값도 받을 수 있어야 한다!

그러면 start 함수가 있는 server.js의 코드도 조금 수정해 줘야 합니다 ㅎㅎ

let http = require("http");
let url = require("url");

function start(route, handle) {
  function onRequest(request, response) {
    let pathname = url.parse(request.url).pathname;
    route(pathname, handle);

    response.writeHead(200, { "Content-Type": "text/html" });
    response.write("Hello Node.js");
    response.end();
  }

  http.createServer(onRequest).listen(8888);
}

exports.start = start;

start 함수의 인자로 handle을 추가해 주고 route에 pathname과 더불어 handle도 넘겨줘요.

그러면 route를 제공하는 router에도 이 사실을 알려줘야합니다 !!

function route(pathname, handle) {
  console.log("pathname: " + pathname);

  handle[pathname]();
}

exports.route = route;

router.js 파일에도 handle을 전달해줍시다
❗️TypeError: handle[pathname] is not a function
    at route (/Users/jin/Desktop/WebStart/router.js:4:19)
    at Server.onRequest (/Users/jin/Desktop/WebStart/server.js:7:5)
    at Server.emit (node:events:512:28)
    at parserOnIncoming (node:_http_server:1067:12)
    at HTTPParser.parserOnHeadersComplete (node:_http_common:119:17)
요런 오류가 발생하네요,,

슬랙에서 답변해 주신걸 보고 수정했습니다 (감사합니다 👾)

function route(pathname, handle) {
  console.log("pathname: " + pathname);

  if (typeof handle[pathname] === "function") {
    handle[pathname]();
  } else {
    console.log("No request handler found for " + pathname);
  }
}

exports.route = route;

이렇게 수정했어요!

requestHandler.js 파일에서 설정 해 준 것처럼 /일때는 main이 출력되고 /login 일때는 login이 출력되는걸 볼 수 있어요

 

 

 

11. URL에 따라 프론트엔드에 다른 response 보내기

현재는 계속 서버를 구동하면 url이 바뀌어도 Hello Node.js만 뜨고 있어요

 

function start(route, handle) {
  function onRequest(request, response) {
    let pathname = url.parse(request.url).pathname;
    route(pathname, handle, response);

server.js

 

function route(pathname, handle, response) {
  console.log("pathname: " + pathname);

  if (typeof handle[pathname] === "function") {
    handle[pathname](response);
  } else {
    console.log("No request handler found for " + pathname);
  }

router.js

 

function main(response) {
  console.log("main");
}

function login(response) {
  console.log("login");
}

requestHandler.js 

 

이렇게 각 파일들의 인자에 response를 추가 해 주고 server.js 파일 내의

   response.writeHead(200, { "Content-Type": "text/html" });
    response.write("Hello Node.js");
    response.end();

를 잘라와서, response를 이제 route 주고,,, route는 handler 주었기 때문에 결과적으로 requestHandler.js파일에서 불러와 줘야 해요

 

function main(response) {
  console.log("main");

  response.writeHead(200, { "Content-Type": "text/html" });
  response.write("Main Page");
  response.end();
}

function login(response) {
  console.log("login");

  response.writeHead(200, { "Content-Type": "text/html" });
  response.write("Login Page");
  response.end();
}

이렇게 !

 

이제 url에 따라 화면에 보이는 메시지가 달라집니다 !!

 

그렇다면 없는 url을 입력한다면.. ? 에 대한 처리는 이미 위에서 오류가 났을때 if문으로 처리를 해 주었습니다 ㅎㅎ!!

이렇게 없는 url을 입력하면 No request handler found for  + pathname이 출력됩니다 

 

송아쌤 버전으로 수정해보면 router.js를

function route(pathname, handle, response) {
  console.log("pathname: " + pathname);

  if (typeof handle[pathname] === "function") {
    handle[pathname](response);
  } else {
    response.writeHead(404, { "Content-Type": "text/html" });
    response.write("Not Found");
    response.end();
  }
}

exports.route = route;

이렇게 수정하고 서버를 다시 실행 해 보아요

이렇게 Not Found가 출력됩니다 

 

 

하 ,,, node.js에서 서버를 구동한것도 이번이 처음이었거든요 ,,
약간 처음 react 컴포넌트 분리할때의 그 기분을 ㅎㅎ 오랜만에 느꼈습니다.. (복습 필수.. ~)
송아쌤이 코드 쪼금만 작성해도 너무너무 잘했다면서 칭찬해주셔서 ㅜㅜ 정말 감사.. 제 자존감 지킴이십니다.. 
복습하고 더 열심히 해봐야겠어요 (:ᘌꇤ⁐ꃳ 三

 

앟 그리고 TIL 작성할때 쫌쫌 쓰기 좋은 이모티콘이 많은 사이트를 공유 해 드립니다.. 

https://wepplication.github.io/tools/charMap/#emoticon