SSE(Server-Sent Events)란?

혜연·2025년 8월 7일
0

📡 SSE란?

SSE 사용법 자세히 보기 (MDN)
SSE는 Server-Sent Events로, 서버에서 클라이언트로 단방향 이벤트 스트림을 전송하는 기술이다.

🔍 언제 사용하면 좋을까?

웹에서 실시간 통신을 구현할 때는 주로 아래 3가지 방식을 고려한다. 상황에 맞게 선택하는 것이 중요하다.

📌 Polling (폴링)

2~3초마다 주기적으로 서버에 요청을 보내는 방식이다.

  • 구현은 가장 간단하지만, 불필요한 요청이 반복되어 서버 부담이 큼
  • 정달 간단한 구현, 테스트할 때 사용하자.

📌 WebSocket (웹소켓)

최초 한 번만 HTTP 요청으로 연결을 맺은 후, 쌍방향 통신을 지속적으로 유지한다.

  • 단점은 초기 설정이나 구현이 복잡하다는 점
  • 채팅, 실시간 협업 등 클라이언트-서버 간 상호작용이 많을 때 사용하자.

📌 SSE (Server-Sent Events)

HTTP 기반의 단방향 통신 방식으로, 서버에서 클라이언트로만 데이터 전송이 가능하다.

  • 웹소켓보다 구현이 간단하고, 브라우저에서 자동 재연결 처리도 수월하다.
  • 알림, 단순한 실시간 업데이트 등에 사용하자.

📎 나의 경험:

무인매장 관리 시스템에서 실시간 알림을 구현할 때 SSE를 사용한 경험이 있다.
이번 프로젝트에서도 읽지 않은 메시지 수를 실시간으로 업데이트 하기 위해 SSE를 선택했다.


EventSource

브라우저에서 기본적으로 제공하는 EventSource 객체를 이용해 서버와 SSE 연결을 할 수 있다.

  eventSource = new EventSource(
    `${process.env.VUE_APP_API_BASE_URL}/sse/subscribe?token=${token}`
  );

  eventSource.addEventListener("unread-count", (event) => {
    try {
      const data = JSON.parse(event.data);
      callback(data);
      console.log("unread-count 이벤트 data:", data);
    } catch (error) {
      console.error("SSE unread-count 데이터 파싱 에러", error);
    }
  });

  eventSource.onerror = (error) => {
    console.error("SSE 연결 오류", error);
    disconnectSSE();
  };

⚠️ 알아야 할 점

  • EventSourceGET 메서드만 지원하고, 헤더 설정이 불가능하다.
  • 위 코드처럼 쿼리스트링으로 토큰을 넘기는 방식은 보안상 안전하지 않을 수 있다. (URL 로그에 토큰이 노출될 수 있음)

Event-source-polyfill

EventSource와 사용법은 거의 동일하나 헤더를 직접 추가할 수 있는 라이브러리이다.
그래서 나는 이 라이브러리로 헤더에 token을 보내는 방법으로 수정했다.

✅ 설치

npm install event-source-polyfill

✅ 적용 코드

import { EventSourcePolyfill } from "event-source-polyfill";

  eventSource = new EventSourcePolyfill(
    `${process.env.VUE_APP_API_BASE_URL}/sse/subscribe`,
    {
      headers: {
        Authorization: `Bearer ${token}`,
      },
      withCredentials: true,
    }
  );

🖥️ 서버(Spring Boot)도 함께 수정

기존에는 @RequestParams으로 토큰을 받았다면, 이제는 @RequestHeader로 헤더를 받아 처리한다.

    // MediaType.TEXT_EVENT_STREAM_VALUE : SSE를 위한 HTTP 응답 타입 설정 이다.
    // 이걸 설정하면 프론트가 sse 스트림이라고 인식할 수 있다.
    @GetMapping(value = "/subscribe", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public SseEmitter subscribe(@RequestHeader("Authorization") String authorizationHeader){
        String token = authorizationHeader.replace("Bearer ", "");

        Claims claims = Jwts.parserBuilder()
                .setSigningKey(secretKey)
                .build()
                .parseClaimsJws(token)
                .getBody();

        String email = claims.getSubject();
        System.out.println(email + " SSE 구독 연결됨");
        return sseService.subscribe(email);
    }

MediaType.TEXT_EVENT_STREAM_VALUE을 지정하면 프론트가 스트림을 응답으로 인식할 수 있다.


🔍 연결 확인 방법

개발자 도구(F12) → Network 탭에서 연결 상태 및 메시지를 확인할 수 있다. (물론 서버 로그로도 확인 가능)

  1. subscribe 요청 확인

  2. Headers : 인증 헤더 포함 여부, 상태코드(200/401) 확인

  3. Response : 실시간 전달되는 메시지 스트림 확인

0개의 댓글