본문 바로가기

코딩/NodeJS

nodejs로 실시간 채팅 기능 만들기

반응형

1. 개요

  • 실시간으로 DB데이터를 가져오는 방법을 알아야 함

2. 알고리즘

  • 서버랑 유저랑 실시간 소통채널(Server Sent Events)을 열어야 함
    • 서버가 유저에게 일방적으로 데이터 실시간 전송 가능
  • HTTP 요청시 몰래 전달되는 정보들이 있음(유저의 언어, 브라우저 정보, 쿠키, 위치정보 등) 이런 정보는 Header에 담겨있음
    • 이 Header를 수정하면 서버와 유저간 실시간 소통 창구 열 수 있음
  • MongoDB Change Stream이란거 쓰면 DB가 업데이트될때마다 유저에게 데이터 쏴줄 수 있음

3. 코드

(1) server.js

// 서버-유저 실시간 소통 코드
app.get("/message/:id", 로그인했니, function (req, res) {
  // Header 셋팅
  res.writeHead(200, {
    "Connection": "keep-alive",
    "Content-Type": "text/event-stream",
    "Cache-Control": "no-cache",
  });
  // 유저에게 해당 채팅방의 데이터 발신
  db.collection("message")
    .find({ parent: req.params.id })
    .toArray()
    .then((결과) => {
        console.log('여긴정상1');
      // 이벤트명 작명해주세여
      res.write("event: test\\n");
      // 결과값을 JSON 데이터로 바꿔서 전송해야 안깨짐
      res.write("data:" + JSON.stringify(결과) + "\\n\\n");
    });
  // ChangeStream 사용 설정
  // parent 게시물이 req.params.id인 게시물만 감시해줌
  const pipeline = [{ $match: { "fullDocument.parent": req.params.id } }];
  // message collection을 감시해줌
  const collection = db.collection("message");
  // watch가 실시간 변동사항 감시 기능
  const changeStream = collection.watch(pipeline);
  // 변동 생기면 여기 코드 실행됨
  changeStream.on("change", (result) => {
    console.log('여긴정상2');
    console.log(result.fullDocument);
    res.write("event: test\\n");
    res.write("data:" + JSON.stringify([result.fullDocument]) + "\\n\\n");
  });
});
  • changeStream이 브라우저와 연결되어있음
  • 유저가 댓글 쓰면 서버가 DB에 댓글 저장함
  • DB는 message collection을 watch하고 있다가 변동사항 발생하면 브라우저로 DB변동사항을 쏴줌

(2) chat.ejs

// 내가 누른 채팅방의 chat collection에서의 게시글ID를 불러옴
      var clickId;

      // 서버와 실시간 소통하는 코드
      var eventSource;
      $(".list-group-item").click(function () {
        clickId = this.dataset.id;
        $(".chat-content").html("");

        // eventSource가 정의되어 있으면 서버 소통 종료
        if (eventSource != undefined) {
          eventSource.close();
        }

        // 서버로부터 실시간 데이터 수신하는 코드
        eventSource = new EventSource("/message/" + clickId);
        eventSource.addEventListener("test", function (e) {
          console.log('여긴정상1');
          // JSON형태의 데이터를 다시 array 형태로 수정해서 찍기
          var 가져온거 = JSON.parse(e.data);
          console.log(가져온거);
          가져온거.forEach(function (i) {
            console.log('여긴정상2');
            // html 태그 생성
            $(".chat-content").append(
              '<li><span class="chat-box">' + i.content + "</span></li>"
            );
          });
        });
      });
  • 채팅방 이름 누르면 해당 채팅방 ID의 댓글 데이터를 모두 불러와서 HTML문서로 만들어줌
  • eventSource가 /message/:id URL로 데이터를 전달받으면 실시간으로 반영해줌
반응형