읽음 상태 조회 (WS + HTTP REST API)

ssongyi·2025년 6월 18일
0

Java/Spring TIL

목록 보기
20/22

읽음(“read receipt”) 상태를 WebSocket 이벤트로만 처리한다면,
클라이언트가 실시간 연결을 못 잡았을 때는 누락될 수 있다.

그래서 보통 이 둘을 함께 제공한다고 한다.

1. WebSocket:

  • 실시간 “누가 읽었는지” 즉시 푸시 알림
  • 채팅 화면 켜져 있을 때 빠르게 반영

2. HTTP REST API:

  • 채팅방 입장 직후나 새로고침 시점에 전체 최신 상태를 한 번에 조회
  • 네트워크 문제로 WebSocket 연결이 끊어졌을 때 보완
  • 모바일·웹 클라이언트가 재접속할 때 초기 동기화 용도

예를 들어, /api/group/{groupId}/chat/rooms/{roomId}/read-status 같은 엔드포인트를 추가해서

GET /api/group/8/chat/rooms/4/read-status
{
  "roomId": 4,
  "lastReadMessageId": 123,    // 로그인한 내가 이 방에서 마지막으로 읽은 메시지 ID
  "unreadCount": 5,            // 읽지 않은 메시지 개수
  "participants": [
    { "userId": 1, "lastReadMessageId": 123 },
    { "userId": 2, "lastReadMessageId": 120 },
    …
  ]
}

이런 식으로 반환해 주면,

  • 화면 진입 시 HTTP로 한 번 동기화하고
  • 이후 WebSocket으로 실시간 업데이트를 받는 흐름이 완성됨

따라서 WebSocket 전용이 아니라, 보완용 HTTP API도 함께 구현하시는 걸 추천한다.


WebSocket 기반 읽음 상태 조회 흐름

1. 클라이언트 요청

사용자가 채팅방에 입장하면, 클라이언트(JavaScript)가 WebSocket 서버에 연결(ws://… or wss://…).

2. 구독(Subscribe)

클라이언트는 특정 채팅방(read-status) 토픽(또는 채널)으로 구독 요청을 보냄.

SUBSCRIBE /topic/chat/rooms/{roomId}/read-status

3. 읽음 이벤트 발생

사용자가 방에 들어오면서 마지막 메시지를 읽으면, 클라이언트는 “읽음” 메시지(read-ack)를 WebSocket으로 전송

SEND /app/chat/rooms/{roomId}/read
Payload: { userId, lastReadMessageId }

4. 서버 처리 & 브로드캐스트

서버에서는 해당 payload를 받아 DB에 ChatParticipant.lastReadMessageId 업데이트 후, 같은 방에 구독 중인 모든 클라이언트에 새 읽음 상태를 푸시(PUBLISH).

PUBLISH /topic/chat/rooms/{roomId}/read-status
Payload: {
  roomId,
  participantStatuses: [
    { userId: A, lastRead: 42 },
    { userId: B, lastRead: 40 },]
}

5. 클라이언트 UI 업데이트

각 클라이언트는 수신한 participantStatuses를 바탕으로 “누가 몇 번째 메시지까지 읽었는지” UI(예: 아바타 옆 체크 표시) 를 실시간으로 갱신


2. HTTP(REST) 기반 읽음 상태 조회

A. Pull 방식 (클라이언트가 주기적으로 조회)

1. 주기적 폴링

클라이언트가 일정 간격(e.g. 5초마다) GET /api/group/{groupId}/chat/rooms/{roomId}/read-status 호출.

2. 서버 처리

  • chatValidator로 그룹·방 권한 검증
  • ChatParticipantRepository로 내 lastReadMessageId와 언읽 개수 계산
  • findActiveByRoom로 모든 참가자의 lastReadMessageId 수집
  • ReadStatusResponse 반환

3. 클라이언트 UI 업데이트

폴링 응답을 받아 WebSocket과 동일한 방식으로 UI 갱신.

B.On-Demand 조회

  • 사용자가 “읽음 상태 보기” 버튼을 눌렀을 때만 한 번 호출
  • 이후에는 WebSocket 알림을 통해 실시간 갱신

전체 비교

구분WebSocketHTTP(REST)
전송방식서버가 클라이언트에 푸시클라이언트가 서버에 풀(Poll) 또는 조회
실시간성즉각적 (이벤트 발생 시 바로 전달)폴링 주기에 따라 지연 발생 가능
부하(Push vs Poll)사용자 수·이벤트 수만큼 메시지 전송조회 빈도×사용자 수 만큼 HTTP 요청 발생
구현 복잡도WebSocket 연결·토픽 구독·브로드캐스트 로직 필요단순 REST 컨트롤러 + 주기적 호출 스케줄링
사용 시나리오1:1 대화·그룹 대화 같은 실시간 채팅부하가 높거나 간헐적 확인이 필요할 때

권장 패턴

1. 주요 실시간 UI 업데이트 → WebSocket

2. 백업/보완용(화면 전환 시 즉시 상태 동기화) → HTTP 한 번 조회

즉, 페이지 진입 직후 GET /read-status로 초기 상태를 받아오고, 이후 WebSocket으로 실시간 변화를 처리하는 하이브리드 방식을 많이 씀

Tip: 폴링 주기를 너무 짧게 잡으면 서버에 부담이 커지고, 너무 길게 잡으면 사용자 경험이 떨어집니다. WebSocket이 여의치 않을 때만 5–10초 주기의 폴링을 고려해 보기

0개의 댓글