ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 노드 POST, PUT, DELETE 요청 보내기
    노드 2023. 4. 13. 14:19

    서버쪽 소스를 다시 한번 보자.

    //restServer.js
    const http = require('http');
    const fs = require('fs').promises;
    
    const users = {}; // 데이터 저장용
    
    http.createServer(async (req, res) => {
      try {
        if (req.method === 'GET') {
          if (req.url === '/') {
            const data = await fs.readFile('./restFront.html');
            res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
            return res.end(data);
          } else if (req.url === '/about') {
            const data = await fs.readFile('./about.html');
            res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
            return res.end(data);
          } else if (req.url === '/users') {
            res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });
            return res.end(JSON.stringify(users));
          }
          // /도 /about도 /users도 아니면
          try {
            const data = await fs.readFile(`.${req.url}`);
            return res.end(data);
          } catch (err) {
            // 주소에 해당하는 라우트를 못 찾았다는 404 Not Found error 발생
          }
        } else if (req.method === 'POST') {
          if (req.url === '/user') {
            let body = '';
            // 요청의 body를 stream 형식으로 받음
            req.on('data', (data) => {
              body += data;
            });
            // 요청의 body를 다 받은 후 실행됨
            return req.on('end', () => {
              console.log('POST 본문(Body):', body);
              const { name } = JSON.parse(body);
              const id = Date.now();
              users[id] = name;
              res.writeHead(201, { 'Content-Type': 'text/plain; charset=utf-8' });
              res.end('ok');
            });
          }
        } else if (req.method === 'PUT') {
          if (req.url.startsWith('/user/')) {
            const key = req.url.split('/')[2];
            let body = '';
            req.on('data', (data) => {
              body += data;
            });
            return req.on('end', () => {
              console.log('PUT 본문(Body):', body);
              users[key] = JSON.parse(body).name;
              res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
              return res.end('ok');
            });
          }
        } else if (req.method === 'DELETE') {
          if (req.url.startsWith('/user/')) {
            const key = req.url.split('/')[2];
            delete users[key];
            res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
            return res.end('ok');
          }
        }
        res.writeHead(404);
        return res.end('NOT FOUND');
      } catch (err) {
        console.error(err);
        res.writeHead(500, { 'Content-Type': 'text/plain; charset=utf-8' });
        res.end(err.message);
      }
    })
      .listen(8082, () => {
        console.log('8082번 포트에서 서버 대기 중입니다');
      });

    /about 요청은 직접 주소에다가 입력을 할 수 있지만 기본적으로 a태그는 GET요청이기 때문에 단순히 

    localhost:8082 페이지에서 Home About a태그를 누르면 /about 부분이 실행된다. 

     

    *css 나 js 파일들을 가져오는 부분이 있었다.

    //restFront.html
    <!DOCTYPE html>
    <html lang="ko">
    <head>
      <meta charset="utf-8" />
      <title>RESTful SERVER</title>
      <link rel="stylesheet" href="./restFront.css" />
    </head>
    <body>
    <nav>
      <a href="/">Home</a>
      <a href="/about">About</a>
    </nav>
    <div>
      <form id="form">
        <input type="text" id="username">
        <button type="submit">등록</button>
      </form>
    </div>
    <div id="list"></div>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    <script src="./restFront.js"></script>
    </body>
    </html>

    <link rel="stylesheet" href="./restFront.css" />

    <script src="./restFront.js"></script> 

    이런 부분도 다 서버에 GET 요청을 보내는 부분이다. 따라서 이런 부분들은 /about 또는 /users에 해당이 되지 않음으로

    GET의 try부분이 실행이 된다. 여기서도 해당이 되지 않는다면 catch가 실행이 된다.

     

    다음은 등록버튼을 눌렀을 때이다.

    인풋 박스에 123123 이라고 입력을 하고 등록을 누르면 restFront.html 에서 form 부분이 실행이 된다. 

    //restFront.html
    <!DOCTYPE html>
    <html lang="ko">
    <head>
      <meta charset="utf-8" />
      <title>RESTful SERVER</title>
      <link rel="stylesheet" href="./restFront.css" />
    </head>
    <body>
    <nav>
      <a href="/">Home</a>
      <a href="/about">About</a>
    </nav>
    <div>
      <form id="form">
        <input type="text" id="username">
        <button type="submit">등록</button>
      </form>
    </div>
    <div id="list"></div>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    <script src="./restFront.js"></script>
    </body>
    </html>

    이 form 부분은 restFront.js와 연결이 되어 있다. 

    //restFront.js
    async function getUser() { // 로딩 시 사용자 가져오는 함수
      try {
        const res = await axios.get('/users');
        const users = res.data;
        const list = document.getElementById('list');
        list.innerHTML = '';
        // 사용자마다 반복적으로 화면 표시 및 이벤트 연결
        Object.keys(users).map(function (key) {
          const userDiv = document.createElement('div');
          const span = document.createElement('span');
          span.textContent = users[key];
          const edit = document.createElement('button');
          edit.textContent = '수정';
          edit.addEventListener('click', async () => { // 수정 버튼 클릭
            const name = prompt('바꿀 이름을 입력하세요');
            if (!name) {
              return alert('이름을 반드시 입력하셔야 합니다');
            }
            try {
              await axios.put('/user/' + key, { name });
              getUser();
            } catch (err) {
              console.error(err);
            }
          });
          const remove = document.createElement('button');
          remove.textContent = '삭제';
          remove.addEventListener('click', async () => { // 삭제 버튼 클릭
            try {
              await axios.delete('/user/' + key);
              getUser();
            } catch (err) {
              console.error(err);
            }
          });
          userDiv.appendChild(span);
          userDiv.appendChild(edit);
          userDiv.appendChild(remove);
          list.appendChild(userDiv);
          console.log(res.data);
        });
      } catch (err) {
        console.error(err);
      }
    }
    
    window.onload = getUser; // 화면 로딩 시 getUser 호출
    // 폼 제출(submit) 시 실행
    document.getElementById('form').addEventListener('submit', async (e) => {
      e.preventDefault();
      const name = e.target.username.value;
      if (!name) {
        return alert('이름을 입력하세요');
      }
      try {
        await axios.post('/user', { name });
        getUser();
      } catch (err) {
        console.error(err);
      }
      e.target.username.value = '';
    });

    마지막 부분의 document.getElementById('form').addEventListener('submit', async (3) => { 

    restFront.html의 form 부분이 실행되면 위의 코드 부분이 실행된다.

    try 문에 보면 post 메서드를 쓰고 url은 /user 인 것을 확인 가능 하다.

     

    그러면 서버에서도 post, user 요청에 맞는 응답을 구현해 주어야 한다. 

    restServer.js 에 POST 그리고 /user 요청에 응답해주는 코드가 있는 것을 찾을 수 있다. 

    단, POST 요청은 데이터가 들어가기 때문에 데이터를 처리를 해 주어야 한다. 

    코드를 보고 이런식으로 데이터를 받는구나~ 라고 생각하면 되겠다. 형식을 그냥 외우면 된다. 

    좀 더 설명하자면 데이터들을 chunk로 받아서 마지막에 body에서 최종적으로 받은 데이터들을 핸들링 한다.  

     

    *웹 브라우저(크롬 기준)의 개발자 도구에서 네트워크 탭에 들어가서 요청이 처리가 됐는지 확인이 가능하다.

    POST 메서드의 요청이 201상태 즉, 잘 처리된 것을 볼 수 있다. 

    데이터는 Body 에서 {key : value} 형식으로 전달된 것을 확인 가능하다.

     

    데이터의 수정인 PUT 그리고 데이터의 삭제인 DELETE 요청 또한 이런 흐름으로 작동된다. 

    실제로 해보고 데이터를 어떻게 받고 수정하고 삭제는 어떻게 하는지에 대한 형태나 문법들을 잘 숙지하는 것이 중요하다. 

    적어도 서버단, 프론트단에서 이런식으로 데이터를 주고받는 것에 대한 흐름은 확실히 잡고 가는 것이 좋겠다. 

     

    추가로 200. 201, 404 등등, 이런 것을 http 상태 코드라고 한다.

    http 상태 코드에 대한 것은 아래 공식 문서에서 확인해 보는 것이 좋다. 

    https://developer.mozilla.org/ko/docs/Web/HTTP/Status

     

     

     

    '노드' 카테고리의 다른 글

    노드 세션 사용하기  (0) 2023.04.13
    노드 쿠키 이해하기  (1) 2023.04.13
    노드 REST API 서버 만들기  (1) 2023.04.13
    노드 fs로 HTML 읽어 제공하기  (0) 2023.04.13
    노드 http 서버 만들기  (0) 2023.04.13
Designed by Tistory.