본문 바로가기
> 개발/Node.js & Express

Node.js 요청 데이터 보내기, request.on()과 response.end()

by @일리 2023. 7. 30.

목표

1. Node.js만 사용하기 - Express 사용 X

2. httpie를 사용해서 서버와 통신하기

3. CRUD 기능 구현하기

필요 데이터

User   Posting  
id PK postingId PK
name   userId FK
email   title  
password   content  
    date  

API 명세서

  매서드 url   매서드 url
유저 정보 전체 보기 GET /user 포스팅 전체 보기 GET /post
유저 정보 추가 POST /user/register 포스팅 작성 POST /post/write
유저 정보 수정 PATCH /user/update/{id} 포스팅 수정 PATCH /user/update/{id}
유저 정보 삭제 DELETE /user/delete/{id} 포스팅 삭제 DELETE /user/delete/{id}
특정 유저의 정보와
포스팅 보기
GET /user/postingList/{Id}      

요청 라우터

const server = http.createServer((req, res) => {
  console.log("-----START------");
  const { url, method } = req;
  res.setHeader("content-type", "application/json");

  if (method === "GET") {
    if (url === "/user") {
      getUserList(req, res);
      return;
    }
    if (url === "/post") {
      getPostList(req, res);
      return;
    }
    if (url.startsWith("/user/postingList/{Id}")) {
        let params = url.split("/")[3];
      getUnifiedData(req, res);
      return;
    }
  }
  if (method === "PATCH") {
        let params = url.split("/")[3];

    if (url.startsWith("/user/update/")) {
      patchUpdateUserInfo(req, res, params);
      return;
    }
    if (url.startsWith("/post/update/")) {
      patchUpdatePosting(req, res, params);
      return;
    }
  }
  if (method === "POST") {
    if (url === "/user/register") {
      postSignUp(req, res);
      return;
    }
    if (url === "/post/write") {
      postWritePost(req, res);
      return;
    }
  }
  if (method === "DELETE") {
    let params = url.split("/")[3];
    if (url === "/user/delete") {
      deleteUserInfo(req, res, params);
      return;
    }
    if (url === "/post/delete") {
      deletePosting(req, res, params);
      return;
    }
  } else {
    resError(req, res);
  }
});

처음에 수정할 정보를 모두 body에 담아 보내는 코드로 작성했다가 나중에 url에서 params로 target userId나 postingId를 식별하고, 변경할 내용은 body에 담아 보내는 코드로 수정을 했다. 

 

각 method와 url에 따라 동작할 함수는 

const getUserList = (req, res) => {
  res.end(JSON.stringify(users));
  console.log("유저들 정보 전송!!");
};

const getPostList = (req, res) => {
  res.end(JSON.stringify(posts));
  console.log("포스트 정보 전송!!");
};

이런 식으로 따로 만들어두었다. 코드를 전체 공개하기엔 너무 길어서 CRUD 기능을 구현하며 정리하고 싶었던 개념만 다루겠당

HTTP 요청에서 데이터를 보내는 방법

1. 매개변수(params)로 보내기

Node.js에서 url에 담긴 params를 확인하려면 url.split("/")으로 url을 분할해야 한다. 그러면 url의 각 데이터들이 배열에 ["", "user", "update", "123"] 담긴다. 이 중 원하는 데이터가 있는 인덱스를 찾아서 parmas 변수에 담은 뒤 활용하면 된다. HTTpie로 요청을 보낼 땐 url 부분에 수정할 유저의 id를 넣고, body에 변경할 이메일 주소를 적었다.

const patchUpdateUserInfo = (req, res, params) => {
  let body = "";

  req.on("data", (data) => (body += data));

  req.on("end", () => {
    const userInfo = JSON.parse(body);
    const userId = params;

    if (!userId) {
      res.statusCode = 400;
      res.end(
        JSON.stringify({ message: "변경할 유저ID를 알려주세요." })
      );
      return;
    }

    const updated = updateUser(userId, userInfo);

    if (updated) {
      res.end(
        JSON.stringify({ message: `${userId}의 정보가 성공적으로 업데이트되었습니다.` })
      );
      console.log(`${userId}의 정보가 성공적으로 업데이트되었습니다.`);
    } else {
      res.statusCode = 404;
      res.end(JSON.stringify({ message: "유저가 없습니다." }));
    }
  });
};


// 요청
http PATCH http://127.0.0.1:3000/user/update/유저id email="email@naver.com"

// 응답
{
    "message": "유저id의 정보가 성공적으로 변경되었습니다."
}

2. 요청 body에 보내기

수정할 대상의 정보와 수정할 내용 모두 body에 담아 보내도 된다. 수정하기 전 코드를 가져왔당

const patchUpdatePosting = (req, res) => {
  let body = "";

  req.on("data", (data) => (body += data));
  req.on("end", () => {
    const postingInfo = JSON.parse(body);
    const postingId = postingInfo.id;
    
	// params에 정보를 보냈을 땐 url에서 postingId를 찾는다.
    // 이번엔 body에 담긴 id로 변경할 postingId를 찾으면 된다.
    
    if (!postingId) {
      res.statusCode = 400;
      res.end(JSON.stringify({ message: "존재하지 않는 포스팅입니다." }));
      return;
    }

    const updated = updatePosting(postingId, postingInfo);
    const idx = posts.findIndex(
      (post) => post.postingId === parseInt(postingId)
    );

    if (updated) {
      res.end(JSON.stringify({ data: { ...posts[idx] } }));
      console.log(`${postingId}번 게시글이 성공적으로 수정되었습니다.`);
    } else {
      res.statusCode = 404;
      res.end(JSON.stringify({ message: "게시글 수정에 실패했습니다." }));
    }
  });
};

// 요청
http PATCH http://127.0.0.1:3000/posting/update/ postingId=2 content="내용을 수정했어요!!"

// 응답
{
    "data": {
        "content": "내용을 수정했어요!!",
        "date": "2023-07-28T00:00:00.000Z",
        "postingId": 2,
        "title": "제목제목",
        "userId": "User3"
    }
}

다른 점은 body에서 postingId를 가져온다는 점이당.

 

HTTP 응답헤더 설정 : setHeader와 writeHead

writerHead는 setHeader + res.statusCode 두 가지의 기능을 가지고 있다.

네이버 응답 헤더

HTTP 응답 헤더는 클라이언트와 서버가 요청 또는 응답으로 부가적인 정보를 전송할 수 있도록 해준다. 대표적으로 사용하는 헤더에는 Content-Type이 있다.

 

// statusCode
response.statusCode = 404;
// setHeader
response.setHeader('Content-Type', 'application/json'); // 대소문자 구분 안함

// writeHead
response.writeHead(200, {
'Content-Type': 'application/json',
'X-Powered-By': 'bacon'
});

 

HTTP 응답 헤더를 설정하기 위해 setHeader(name, value)와 writeHead(statusCode, headers)를 사용할 수 있다. setHeader는 한 번에 하나의 HTTP 응답 헤더를 설정할 수 있다. setHeader와 더불어 상태코드를 설정할 때 response.statusCode = 404;를 사용한다.

res.setHeader('Content-Type', 'application/json');
res.setHeader('Cache-Control', 'no-cache');

이렇게 여러 번 호출해도 된다.

 

writeHead는 setHeader와 statusCode의 기능을 갖고 있다. 한 번에 응답에 대한 상태코드와 헤더를 설정할 수 있다. 다만 HTTP 서버 응답 시 한 번만 사용 가능하다. 여러 번 호출할 경우 첫 번째 호출만 유의미하고, 나머지 호출은 무시한다. 그래서 부가적으로 HTTP 헤더 설정이 필요한 경우 setHeader를 사용해야 한다.

 

request.on()

request.on을 이용해서 HTTP 요청과 관련된 이벤트가 발생했을 때 이벤트를 어떻게 처리할 것인지 정할 수 있다.

request.on은 두 개의 인자를 받는다. 하나는 이벤트 이름, 하나는 지정된 이벤트가 발생했을 때 실행할 콜백함수이다.

 

request.on의 이벤트

1. data : 데이터를 수신할 때 실행할 이벤트

2. end : 클라이언트로부터 모든 데이터를 수신 완료했을 때 실행할 이벤트

3. error : 요청 처리 중 에러가 발생했을 때의 이벤트

request.on 예시

const postWritePost = (req, res) => {
  let body = "";
  req.on("data", (data) => (body += data));
  // data(chunk data)가 들어올 때마다 body에 chunk data를 넣는다.
  req.on("end", () => {
  // 클라이언트로부터 모든 data를 수신하면 실행한다.
    const post = JSON.parse(body);
  // body를 파싱해서 자바스크립트 객체로 만든다.
    posts.push({
      id: post.id,
      title: post.title,
      content: post.content,
      date: new Date(),
      name: post.name,
    });
  // posts에 새로운 게시글 정보를 추가한다.
    res.end(JSON.stringify("게시물이 정상적으로 등록되었습니다."));
    console.log("게시물 추가 완료!!!");
  });
};

response.end()

response.end()는 HTTP 응답의 종료와 클라이언트에게 데이터를 동시에 보낼 때 사용한다. 한 번에 데이터를 보내고 통신을 종료하기 때문에 한 번만 호출할 수 있다. 

// 간단한 문장으로 응답을 보낼 수 있다.
 res.end('Hello, World!');
 
// 혹은 JSON 형태로 응답을 보낼 수 있다.
 res.end(
    JSON.stringify({ message: "User ID is missing in the request." })
      );

response.end()와 비슷한 개념으로 response.end()가 있다.

 

response.write()는 청크 단위로 클라이언트에 데이터를 보낼 때 사용한다. 여러 번 반복해서 보낼 수 있으며, 통신의 연결에는 아무런 영향을 주지 않기 때문에 response.write()로 데이터를 보낸 뒤 response.end()로 통신이 끝났다는 신호를 보내야 한다.

 

확실히 직접 기능을 구현하면서 코드를 작성해보고, 궁금했던 개념들을 정리하니 학습이 잘된당!! 다음엔 Express도 연습해봐야지. 화이팅이당~!!

댓글