React로 Stomp와 Socket을 이용한 채팅방 구현하기

jaehan·2022년 12월 15일
10

React

목록 보기
18/33
post-thumbnail

이번학기 프로젝트에서 채팅방을 구현했는데, 처음엔 어려웠지만 한번 이해하고 나니 쉽게 느껴져서 정리해보려 한다.

🖥 개발환경: React, Stomp, SocketJs + Spring

개념 이해하기

Socket

양방향 통신/소통을 할때 음성/텍스트/이미지 등의 데이터가 전송되는 도착지점.
데이터가 도착하는 지점들.

SocketJs

WebSocket과 유사한 객체를 제공하는 브라우저 라이브러리

  • websocket을 지원하지 않는 브라우저 에서도 사용 가능
  • 브라우저와 웹 서버 사이에서 짧은 지연시간, 크로스 브라우징을 지원하는 API

Stomp

HTTP에서 모델링 되는 Frame 기반 프로토콜

  • publish-subscribe구조로 되어있다.
  • react-spring 협업할때 주로 사용한다 함.
  • 헤더 값을 기반으로 통신 시 인증처리를 구현 할 수 있음.

📌 Message Broker

이게 가장 중요한 부분인데 이부분을 이해하면 구현 할 때 어렵지 않을 것 이다.

Message Broker는 Subscriber(구독한 사람들)에게 Publish(발행한) 메세지를 보내주는 중간 역할을 함.
이해하기 쉽게 말하면 sub는 채팅방 입장이고, pub는 메세지 보내기 이다.

구현하기

우선 프로젝트에서 구현한 방법은

  1. 채팅방(id는 랜덤값으로 되이있다)에 입장한다.
  2. 채팅방에 입장하자 마자 stomp서버에 연결한다.
  3. 연결 후에 채팅방 id값을 sub(구독) 한다.
  4. 입장된 채팅방에서 메세지를 보내면 pub(발행)해서 모든 구독자들에게 메세지를 Stomp서버가 뿌려준다.

install

typescript를 사용하기 때문에

stompjs

npm install @stomp/stompjs
// 버전 때매 안되면 --force 뒤에 붙혀준다

socketjs

npm install sockjs-client
// 버전 때매 안되면 --force 뒤에 붙혀준다

Conncet, Subscribe

const client = useRef<CompatClient>();

const connectHaner = () => {
  clicent.current = Stomp.over(() => {
    const sock = new SockJS("http://localhost:8080/{백에서 설정한 end point}")
    return sock;
  });
  client.current.connect(
    {
      // 여기에서 유효성 검증을 위해 header를 넣어줄 수 있음.
      // ex) 
	  Authorization: token
    },
    () => {
      // callback 함수 설정, 대부분 여기에 sub 함수 씀
      client.current.subscribe(
     	`/백엔드와 협의한 api주소/{구독하고 싶은 방의 id}`,
        (message) => {
          setMessage(JSON.parse(message.body));
        },
        {
          // 여기에도 유효성 검증을 위한 header 넣어 줄 수 있음
        }
      );
    }
  );
}

connect 함수는 ({헤더}, 콜백함수 ()=>{})로 구성된다.

우선 렌더링 최적화를 위해 client를 ref로 설정해 주었다.

endpoint는 백에서 설정한 주소인데 나는 스프링과 연동하고 로컬 환경이기 때문에
"http://localhost:8080/ws-stomp" 이렇게 설정해 주었다

connect 안에는 유효성 검사를 위해 axios header에 담겨있는 토큰을 헤더에 넣어줬고

콜백 함수에는 subscribe 함수를 넣어줬다.

subscribe 함수는 (주소, 콜백함수 ()=>{}, {헤더}) 로 구성된다

주소는 채팅방의 아이디 값을 넣어주고

콜백함수에는 구독한 방에서 publish(발행)한 메세지에 대한 처리를 해주는 곳인데 나는 따로 메세지를 관리하는 state에 넣어줬다.

message body 형식은 아래와 같기 때문에 JSON.parse()로 묶어줬다.

{
  type: string;  // TALK(메세지) or ENTER(입장할 때)
  roomId: string;  // 방의 주소
  sender: string;  // 보낸 사람
  message: string;  // 메세지
}

💡 마무리로 나는 위의 connect와 subscribe를 묶은 connectHandler 함수를 방을 클릭해 방에 입장할때 onClick 이벤트 안에 넣어줬다.

Publish(send)

const sendHandler = () => {
	client.current.send(
      "/백엔드와 협의한 api주소",
      {헤더},
      JSON.stringify({
        type: "TALK",
        roomId: roomId,
        sender: user.name,
        message: inputMessage
      })
    );
};

Publish 함수는 (주소, {헤더}, 메세지)로 구성된다.

❗️ 최근에는 publish대신 send를 사용한다고 한다.

메세지 형식은 백엔드와 협의해서 정하면 되는데 우리는 위에 말한 타입으로 줬고
roomId를 확인해서 백에서 해당 room에 메세지를 뿌려주는 형식이다.

💡 이 sendHandler함수를 메세지 보내기 버튼에 onClick이벤트 안에 넣어줬다.

마무리

메세지리스트 관리나 방 리스트 관리는 자기 편한 대로 사용 하면 되고 connect, subscribe, send가 가장 중요 한것 같다!
나머지 코드는 github

구현 완료한 채팅방이다.

참고
https://dev-gorany.tistory.com/235

0개의 댓글