본문 바로가기

Node.js

Node.js(11) - AJAX 기본 포맷, server 분리(front/back) 구현

728x90
반응형

1) Node.js

   1-1) 비동기 통신의 기본 로직(AJAX 기본 포맷)

   1-2) server 분리(front, back) 후 AJAX 구현

 

 

 

 

 

1) Node.js

1-1) 비동기 통신의 기본 로직(AJAX 기본 포맷)

GET  /  index.html
GET  /ajax  GET
POST  /ajax  POST

$ npm init -y
$ npm install express


※ 브라우저가 "Content-Type"에 따라 읽는 모드가 달라진다! --> 이로 인해 "Content-Type"이 달라지면 요청을 새로 다시 보낸다!!
url을 안바꾸고 요청을 만들어서 보내는 것이 "AJAX"의 기본원리이다!!

 

 

server.js

 
const express = require("express");
const nunjucks = require("nunjucks");
const app = express();

app.use(express.static("public")); // server.js 파일을 기준으로 "public" 디렉토리 안의 모든 디렉토리와 파일들을 router로 만들겠다는 의미이다!!
app.use(express.urlencoded({ extended: false })); // query string(Content-type) 데이터를 읽을 수 있는 body parser 역할을 하는 코드
app.use(express.json()); // JSON(Content-type) 타입을 읽을 수 있는 body parser 역할을 하는 코드

app.set("view engine", "html");
nunjucks.configure("views", {
  express: app,
});

app.get("/", (req, res) => {
  res.render("index.html");
});

app.get("/ajax", (req, res) => {
  console.log("GET /ajax 요청 옴!!");
  const userid = req.query.userid;
  let flag = true;
  if (userid === undefined) {
    flag = false;
  }
  console.log(req.query.userid, flag);
  // res.status(404).send("test~~~!!"); // 이를 통해 상태코드를 200(default 값)에서 404로 바꿔줄 수 있음!!
  // res.status(200).send("true");
  res.status(200).send(`${flag}`);
});

app.post("/ajax", (req, res) => {
  console.log("POST /ajax 실행됨!!");
  const userid = req.body.userid;
  let flag = true;
  if (userid === undefined) {
    flag = false;
  }
  res.send(`${flag}`);
});

app.listen(3000, () => {
  console.log("server start");
});

 

views/index.html

<!DOCTYPE html>
<html lang="en">
  <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>
    test입니다~~
    <!-- GET /ajax -->
    <button id="ajax_get">ajax_get</button>
    <button id="ajax_post">ajax_post</button>

    <p id="msg"></p>
    <script type="text/javascript" src="/js/index.js"></script>
  </body>
</html>

 

public/js/index.js

// XMLHttpRequest 메서드를 사용하여 요청을 보냄!!

// new 키워드를 통해 XMLHttpRequest 메서드가 class 혹은 생성자 함수 형태임을 확인할 수 있음!!
const xhr = new XMLHttpRequest(); // {open:()=>{}, setRequestHeader:()=>{}, send:()=>{}, onload:()=>{}}
// open

const ajax_get = document.querySelector("#ajax_get");
const ajax_post = document.querySelector("#ajax_post");
const msg = document.querySelector("#msg");
ajax_get.addEventListener("click", () => {
  // console.log(xhr);

  xhr.open("get", "http://localhost:3000/ajax?userid=web7722");
  xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
  // 여기까지는 request message를 만드는 과정이고, 아래 send 메서드를 사용하여 실제 request message를 날린다!!
  xhr.send(); // 여기서 진짜 요청이 날아간다!(위의 코드들은 사전 작업에 해당함!)

  xhr.onload = () => {
    // console.log(xhr.readyState, xhr.status, xhr.response); // 4(응답이 왔다는 의미이다!!) 200(response message의 상태코드에 해당함!!) 'get'(request method가 아니라 response body 영역에 있는 내용임!!)
    // xhr.readyState --> 4
    if (xhr.readyState === 4 && xhr.status === 200) {
      // console.log(xhr.response);
      const response = xhr.response;
      if (response === "true") {
        msg.innerHTML = "아이디가 중복되었습니다.";
        msg.style.color = "red";
      } else {
        msg.innerHTML = "사용 가능한 아이디입니다.";
        msg.style.color = "green";
      }
    }
  };
});

// userid에 "web7722" 값 넣기
ajax_post.addEventListener("click", () => {
  xhr.open("post", "http://localhost:3000/ajax");
  // xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
  // xhr.send("userid=web7722");
  xhr.setRequestHeader("Content-type", "application/json");
  const data = { userid: "web7722" };
  xhr.send(JSON.stringify(data));

  // application/json --> "JSON 객체(ex. userid: "web7722")"를 보내야 함!!
  // application/x-www-form-urlencoded --> "query string(ex. userid=web7722)"을 보내야 함!!
});

// ajax, fetch, axios --> 사용 방법만 다를 뿐 근본적인 목표와 내용은 동일함!!

 

 

 

1-2) server 분리(front, back) 후 AJAX 구현

CORS(host를 기준으로 다른 컴퓨터들끼리 통신하는 것을 막는 역할을 함!!) : HTTP Protocol에서 header에 있음!!
- CORS는 port, 즉 end-point(도착지점)까지 확실히 체크함!!
- CORS 처리는 허용한 사람에게만 주겠다는 의미이다!!(브라우저 기준)

host : 인터넷이 되는 컴퓨터

 

비동기 통신
현재 AJAX를 통해 비동기 통신 흐름을 익히는 것을 목표로 함!

비동기 통신을 배운 목적 : front, back server를 나누기 위함!!

  • 이유 : 비동기 통신을 해야지만 Origin(CORS가 허용한 URI)에 다른 요청을 보낼 수 있기 때문이다.
  • front, back 서버를 나눈 후 ajax 통신을 하다보니 "CORS" 에러(보내는 사람과 받는 사람의 path가 다른 경우에 기능을 막는 것을 의미함)가 발생함!!
  • 이러한 CORS 에러를 막기 위해서는 back server의 response message 상 Origin을 허용한다고 설정해두면 된다!!

 

front

server.js

const express = require("express");
const nunjucks = require("nunjucks");
const app = express();

app.use(express.static("public"));

app.set("view engine", "html");
nunjucks.configure("views", {
  express: app,
});

app.get("/", (req, res) => {
  res.render("index.html");
});

app.get("/ajax", (req, res) => {
  res.send("get");
});

app.post("/ajax", (req, res) => {
  res.send("post");
});

app.listen(3005, () => {
  console.log("server start");
});

 

views/index.html

<!DOCTYPE html>
<html lang="en">
  <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>AJAX</h1>
    <button id="ajax_get">ajax_get</button>
    <button id="ajax_post">ajax_post</button>

    <div id="msg"></div>
    <div id="userlist">
      <!-- <ul>
        <li>1</li>
        <li>web7722</li>
        <li>1234</li>
        <li>sangbeom</li>
        <li>남자</li>
      </ul> -->
    </div>
    <input type="text" name="userid" id="userid" />
    <button id="btn">유저 추가</button>
    <script src="/js/index.js" type="text/javascript"></script>
  </body>
</html>

 

public/js/index.js

const xhr = new XMLHttpRequest();
const ajax_get = document.querySelector("#ajax_get");
const ajax_post = document.querySelector("#ajax_post");
const msg = document.querySelector("#msg");

// request({ method: "get", path: "/users/5", body: "" }, callback);
const request = ({ method, path, body }, callback) => {
  const host = "http://localhost:3000";
  const xhr = new XMLHttpRequest();
  xhr.open(method, `${host}${path}`);
  xhr.setRequestHeader("Content-type", "application/json");
  xhr.send(JSON.stringify(body));

  xhr.onload = () => {
    if (xhr.status === 200) {
      callback(xhr.response);
    }
  };
};

/*
ajax_get.addEventListener("click", () => {
  const view = (xhr) => {
    if (xhr.readyState === 4 && xhr.status === 200) {
      console.log(xhr.response);
    }
  };

  request({ method: "get", path: "/users/1" }, view);
});
*/

ajax_get.addEventListener("click", () => {
  request({ method: "get", path: "/users/1" }, (response) => {
    console.log(response);
  });
});

ajax_post.addEventListener("click", () => {
  request({ method: "post", path: "/users" }, (response) => {
    console.log(response);
  });
});

// 브라우저에 render해주는 코드
const userList = document.querySelector("#userlist");
const btn = document.querySelector("#btn");
const card = ({ idx, userid, userpw, username, gender }) => {
  const ulElement = document.createElement("ul");
  const idxElement = document.createElement("li");
  const idElement = document.createElement("li");
  const pwElement = document.createElement("li");
  const nameElement = document.createElement("li");
  const genderElement = document.createElement("li");

  idxElement.innerHTML = idx;
  idElement.innerHTML = userid;
  pwElement.innerHTML = userpw;
  nameElement.innerHTML = username;
  genderElement.innerHTML = gender;

  ulElement.append(idxElement);
  ulElement.append(idElement);
  ulElement.append(pwElement);
  ulElement.append(nameElement);
  ulElement.append(genderElement);
  userList.append(ulElement);
};

request({ method: "get", path: "/users" }, (response) => {
  const arr = JSON.parse(response);
  console.log(arr);
  arr.forEach((v) => {
    card(v);
  });
});

// 요청 코드
btn.addEventListener("click", () => {
  request(
    {
      method: "post",
      path: "/users",
      body: {
        userid: document.querySelector("#userid").value,
        userpw: "1234",
        username: "sangbeom",
        gender: "남자",
      },
    },
    (response) => {
      // console.log(response);
      card(JSON.parse(response));
    }
  );
  // card({
  //   idx: 2,
  //   userid: "web7722",
  //   userpw: "4567",
  //   username: "sangbeom",
  //   gender: "male",
  // });
});

/*
ajax_get.addEventListener("click", () => {
  xhr.open("get", "http://localhost:3000/users/5");
  xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
  xhr.send();

  xhr.onload = () => {
    if (xhr.readyState === 4 && xhr.status === 200) {
      console.log(xhr.response);
    }
  };
});

ajax_post.addEventListener("click", () => {
  xhr.open("post", "http://localhost:3000/users");
  xhr.setRequestHeader("Content-type", "application/json");
  const data = {
    userid: "web7722",
    userpw: "1234",
    username: "sangbeom",
    gender: "남자",
  };
  xhr.send(JSON.stringify(data));

  xhr.onload = () => {
    if (xhr.readyState === 4 && xhr.status === 200) {
      console.log(xhr.response);
    }
  };
});
*/

 

 

back

server.js

const express = require("express");
const cors = require("cors");
const app = express();

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

// npm install cors
app.use(cors());

// 아래 코드는 "app.use(cors());"로 대체 가능함!!
// app.use((req, res, next) => {
//   res.setHeader("Access-Control-Allow-Origin", "*");
//   res.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
//   res.setHeader("Access-Control-Allow-Headers", "Content-type");
//   next();
// });

const user = [
  {
    idx: 1,
    userid: "web7722",
    userpw: "1234",
    username: "sangbeom",
    gender: "남자",
  },
];

// GET /board/list
// POST /board/write
// GET /board/view
// POST /board/modify
// POST /board/delete

// RESTful API는 기본적으로 단어의 복수형을 사용하도록 하기에 "boards"로 씀!
// path 부분에 동사가 들어가면 안 된다!!

// list --> GET /boards
// view --> GET /boards/1(여기서 1은 고유한 식별자 값에 해당함!!)
// write --> POST /boards
// modify --> PUT /boards
// delete --> DELETE /boards

// list page
app.get("/users", (req, res) => {
  res.json(user); // "res.json"은 "res.send"와 동일하다고 보면 됨!
  // res.send("GET /users");
});

// write page
app.post("/users", (req, res) => {
  const { userid, userpw, username, gender } = req.body;
  const response = {
    idx: user[user.length - 1].idx + 1,
    userid,
    userpw,
    username,
    gender,
  };
  user.push(response);
  // res.send("POST /users");
  res.json(response);
});

// view page
// 해당 코드는 항상 맨 아래에 있어야 잘 동작하기 때문에 맨 아래에 작성할 것을 권한다!!
app.get("/users/:id", (req, res) => {
  // console.log(req.params);
  // res.json(user);
  const { idx } = req.params;
  const [response] = user.filter((v) => v.idx === parseInt(idx));
  res.json(response);
});

app.listen(3000, () => {
  console.log("server start");
});