웹소켓(WebSocket) 성공 기록

Seoyeon·2026년 1월 22일

백엔드

목록 보기
9/27

카이스트 몰입캠프 2주차 프로젝트 결과물인 몰 봐(MV) 서비스의 핵심인 "댓글 기반 팟 모집 -> 채팅방 생성 -> 실시간 채팅" 로직을 바탕으로 웹소켓(WebSocket) 구현 성공 기록기...


1. 웹소켓과 STOMP 기초 개념

단순 웹소켓만 쓰면 로우 레벨이라 메시지 형식을 일일이 다 정해야 함
그래서 우리는 STOMP 규격 사용했음

  • 구조: 메일함처럼 특정 주소를 '구독(Sub)'하고, 그 주소로 메시지를 '발행(Pub)'하는 방식임.

  • 장점: 메시지 브로커를 통해 채팅방별로 메시지를 꽂아주기가 훨씬 편함.

  • Publisher(발행자): 채팅 메시지를 보내는 사람 (클라이언트)

  • Subscriber(구독자): 채팅방에 들어와서 메시지를 받는 사람 (클라이언트)

  • Broker(중개자): 메시지를 받아서 구독 중인 사람들에게 뿌려주는 서버


2. 백엔드 설정 (Spring Boot)

먼저 의존성에 spring-boot-starter-websocket 추가되어 있어야 함.

[WebSocketConfig.java]

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        // 메시지 받을 때: /sub/chat/room/1 이런 식으로 구독함
        config.enableSimpleBroker("/sub"); 
        // 메시지 보낼 때: /pub/chat/message 이런 식으로 보냄
        config.setApplicationDestinationPrefixes("/pub");
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/ws") // 프론트가 접속할 엔드포인트
                .setAllowedOrigins("https://www.example.com") // 프론트 도메인 필수
                .withSockJS(); // 낮은 버전 브라우저 대응
    }
}

3. 채팅 로직 흐름 (우리 서비스 특화)

글쓴이가 게시글(Post) 댓글에서 선택해서 팟 참여 확정 -> 채팅방 생성 구조로 기획을 했음..

  1. 팟 확정: 게시글 작성자가 참여자를 선택하고 '확정' 누름.
  2. 채팅방 생성: 서버에서 ChatRoom 만들고 선택된 인원들을 ChatMember로 등록함.
  3. 알림 발송: 참여자들에게 "채팅방에 초대되었습니다"라고 알림 쏨.
  4. 입장 및 구독: 프론트에서 roomId를 받아 해당 경로(/sub/chat/room/{id})를 구독함.
  5. 메시지 전송(Publish): 유저가 채팅 치면 프론트에서 /pub/chat/message로 JSON 데이터를 전송

[ChatController.java]

@Controller
@RequiredArgsConstructor
public class ChatController {
    private final SimpMessageSendingOperations messagingTemplate;

    @MessageMapping("/chat/message") // 프론트가 /pub/chat/message로 보낼 때
    public void message(ChatMessageDto message) {
        // DB에 채팅 내역 저장하는 로직 추가 가능
        // 구독 중인 사람들에게 메시지 전달
        messagingTemplate.convertAndSend("/sub/chat/room/" + message.getRoomId(), message);
    }
}

4. 프론트엔드와 협업할 때 주의사항

① 보안 및 인증 (가장 많이 막히는 부분)

  • 웹소켓은 일반 HTTP 요청이랑 다르게 Header에 토큰 담기가 까다로움....
  • 해결: 연결 시점(connect)에 쿼리 파라미터로 토큰을 보내거나, STOMP의 connectCallback 헤더에 JWT 토큰을 실어 보내야 함. 백엔드에서 ChannelInterceptor를 구현해서 토큰 검증 로직 따로 짰음

② CORS 에러

  • 웹소켓 엔드포인트(.addEndpoint("/ws"))에도 .setAllowedOrigins 설정을 정확히 해줘야 함. 안 그러면 프론트에서 접속 못 함......

③ 도메인 연결 (HTTPS/WSS)

  • 서비스 HTTPS 적용했다면 프론트도 ws://가 아니라 wss://로 접속해야 함.
  • AWS ALB(로드밸런서) 쓰고 있으면 웹소켓 프로토콜도 지원하도록 설정 확인해야 함 (기본적으로 지원하지만 간혹 타임아웃 이슈 있음).

5. 오류 해결 및 팁

  • 채팅방 자동 생성 이슈: 댓글에서 선택해서 채팅방 만들 때, 선택된 인원들의 Member ID 리스트를 받아서 ChatMember(중간 테이블)에 저장해야 했음. 그래야 나중에 "내 채팅방 목록" 조회할 때 내가 속한 방만 가져올 수 있었음
  • 무한 루프 방지: 프론트에서 메시지 받고 바로 다시 메시지 쏘는 로직 들어가면 서버 터짐. 이벤트 리스너 관리 잘하라고 프론트한테 말해줘서 해야함!

사소하지만 디테일 구현하고자 한 포인트

유저마다 last_read_at(마지막 읽은 시간)을 필드로 둠. 채팅방 목록 불러올 때 이 시간 이후로 쌓인 메시지 개수를 쿼리로 날려서 "안 읽은 메시지 N개" 기능을 구현했음..

0개의 댓글