개발여행

STOMP.js로 프론트엔드에서 웹소켓 통신 구현 본문

Frontend

STOMP.js로 프론트엔드에서 웹소켓 통신 구현

jbilee 2024. 4. 5. 10:27

참여하고 있는 팀 프로젝트에서 계획에는 없었던 실시간 채팅 기능을 만들기로 결정됐다. 노마드코더에서 Socket.IO로 Zoom 클론코딩을 해봤던 경험이 있어서 자신있게 프론트에서는 내가 웹소켓을 맡겠다고 했으나...

 

서버쪽 구현을 맡은 멤버가 처음 들어보는 STOMP로 웹소켓을 구현했다고 해서, 같은 웹소켓이지만 완전 새로운 공부를 하게 됐다.

 

STOMP란?

STOMP는 Simple(또는 Streaming) Text Oriented Messaging Protocol의 약자로, 웹소켓(WebSocket) 환경에서 돌아가는 HTTP 서브프로토콜이다. 메세지 기반 전송에 특화되어 있어서 실시간 채팅 서비스 등을 구현할 때 사용하기 좋다고 한다.

 

STOMP의 구독—발행 구조가 이해하기 쉬워서 다행히 사용법을 빨리 익힐 수 있었다. 물론 STOMP.js라는 라이브러리가 존재했기에 가능한 일이었다.

 

클라이언트 인스턴스 생성과 가동

웹소켓 프로토콜에서 서버와 연결하려면 우선 STOMP.js 클라이언트 객체가 필요하다. 송신자와 수신자가 STOMP 메세지를 주고 받을 수 있도록 중개자(broker) 서버의 URL을 객체를 생성할 때 전달한다.

import { Client } from "@stomp/stompjs";

const client = new Client({
  brokerURL: `ws://주소`,
  connectHeaders: { Authorization: "Bearer " + session.jwt.accessToken },
});

 

STOMP 기반 메세지는 헤더를 사용할 수 있다. 우리 프로젝트의 경우 사용자 검증을 해야 해서 서버에서 요청한 authorization 토큰을 connectHeaders 객체에 추가했다.

 

인스턴스를 생성한 후에는 client.activate() 함수를 실행해야 소켓 연결을 시도한다. 연결이 성공했을 때 실행할 후속 작업은 client.onConnect 이벤트에서 핸들링할 수 있다.

*onConnect 이벤트 핸들러는 클라이언트 인스턴스를 생성할 때에도 미리 전달 가능 (STOMP.js 레포 참고)

client.activate();

client.onConnect = () => {
  // 연결 후의 작업 (구독 등)
};

 

소켓에 연결되면 구독과 발행을 통해 실시간으로 메세지를 전송/수신할 수 있다.

 

구독 (subscribe)

서버로부터 도착한 메세지를 읽기 위해서는 client.subscribe() 메소드를 사용해 올바른 목적지(destination)를 구독해야 한다. 특정 destination을 구독하면 해당 창구를 통해 들어오는 메세지를 프론트에서 받아 처리할 수 있다.

import type { Message } from "@stomp/stompjs";

// 구독한 destination에서 메세지가 들어올 때마다 실행할 콜백
const onServerMessage = (response: Message) => {
  // 서버에서 보낸 메세지 body를 파싱해서 사용
  const message = JSON.parse(response.body);
};

// 구독 - destination과 콜백 함수 전달
client.subscribe("/chat/room/1", onServerMessage);

 

발행 (publish)

발행은 클라이언트에서 서버에 메세지를 보내고자 할 때 실행하는 액션이다. client.publish() 메소드에 destination, 메세지 내용, 헤더 등의 정보가 들어간 객체를 인자로 전달한다.

// 전송할 데이터
const message = { name: "Anon", text: "hello, world" };

// 발행
client.publish({
  destination: "/chat/message",
  body: JSON.stringify(message),
});

 

브로커에 연결할 클라이언트, 구독, 발행만 갖추면 기본적인 STOMP 기능은 다 구현한 것이나 마찬가지다. 비록 STOMP 자체가 메세징 기반이라는 특화된 기술이지만, Socket.IO에서 emit이랑 on 이벤트를 처리하는 것보다 훨씬 눈에 잘 들어와서 비교적 빨리 배울 수 있었던 것 같다.

 

 

참고