SSE — 것이 무엇인지, Server-Sent Events 및 단방향 스트리밍

저자: IT Sectr 게시일: 2026-06-02 읽는 시간: 8 분

SSE(Server-Sent Events)는 서버가 단방향 모드로 하나의 HTTP 연결을 통해 클라이언트에 스트리밍 데이터를 보낼 수 있도록 하는 W3C 표준입니다. WebSocket과 달리 SSE는 일반 HTTP 위에서 작동하고 클라이언트 측에 특별한 프로토콜이나 라이브러리가 필요하지 않습니다. W3C HTML Living Standard(2025) 규격에 따르면 EventSource API는 Chrome, Firefox, Safari 그리고 Edge를 포함한 모든 현대 브라우저에서 지원됩니다.

주요 요점

  • SSE는 HTTP 연결을 통한 서버에서 클라이언트로의 단방향 데이터 전송에 대한 표준입니다.
  • EventSource API는 외부 라이브러리 없이 SSE를 수신하기 위한 내장 브라우저 인터페이스입니다.
  • 자동 재연결 — 연결이 끊긴 경우 브라우저가 자동으로 연결을 복구합니다.
  • 텍스트 프로토콜 — 데이터는 간단한 텍스트 형식으로 text/event-stream 형식으로 전송됩니다.
  • 단방향 통신 — SSE는 알림, 뉴스 피드, 티케 및 모니터링에 적합하지만 채팅에는 적합하지 않습니다.

SSE란 무엇인가?

SSE(Server-Sent Events)는 웹 서버가 연결을 설정한 후 언제든지 클라이언트에 데이터를 보낼 수 있도록 하는 기술입니다. WHATWG에 의해 HTML Living Standard의 일부로 표준화되었고 MIME 타입 text/event-stream을 사용합니다. SSE는 메시지 식별자, 이벤트 유형 및 재연결 지연을 지정할 수 있는 텍스트 데이터 전송을 지원합니다.

양방향 프로토콜과 업그레이드 요청이 필요한 WebSocket과 달리 SSE는 일반 HTTP 위에서 작동합니다. 서버는 Content-Type: text/event-stream 헤더를 설정하고, 데이터를 청크 단위로 보내며 연결을 열어 두너다. 클라이언트는 브라우저의 EventSource API를 통해 데이터를 수신하며, 이는 스트리머를 자동으로 파싱하고 이벤트를 생성합니다.

CanIUse(2025)에 따르면 EventSource API는 글로벌로 97.5% 브라우저에서 지원됩니다. Internet Explorer와 일부 모바일 브라우저(버전 7.0 이전의 Samsung Internet)에서는 지원되지 않습니다. 이러한 경우 XHR 스트리밍을 통해 EventSource를 에뮬레이트하는 폴리필이 있습니다. SSE는 HTTP/1.1 파이프라이닝과 작동하지 않지만 HTTP/2 서버 퓨시와 완전히 호환됩니다.

역사 및 표준화

SSE는 2009년에 Server-Sent DOM Events라는 이름으로 HTML5 규격의 일부로 제안되었습니다. 첫 번째 구현은 Opera 9.0, 그 다음 Firefox 6.0(2011), Chrome 9.0(2011), Safari 5.0(2010)에서 나타났습니다. 2015년에 규격은 HTML Living Standard의 별도 섹션으로 이동되었습니다. 10년 이상의 역사에도 불구하고 SSE는 단방향 특성 때문에 WebSocket보다 더 덕 많이 사용되지 않습니다.

SSE 작동 방식

SSE의 작동 메커니즘은 다음과 같습니다: 클라이언트가 서버 엔드포인트의 URL로 EventSource 인스턴스를 생성합니다. 브라우저는 Accept: text/event-stream 헤더가 있는 GET 요청을 보냅니다. 서버는 200 OK 상태 코드와 Content-Type: text/event-stream 헤더로 응답한 후 event-stream 형식으로 데이터를 보내기 시작합니다. 서버가 종료 신호를 보내거나 클라이언트가 close()를 호출할 때까지 연결은 열려 있습니다.

서버 측에서 데이터는 청크 단위(chunked transfer encoding)로 보내집니다. 각 데이터 청크는 필드 라인(event, data, id, retry)으로 구성된 텍스트 메시지입니다. 서버는 언제든지 메시지를 보낼 수 있으므로 SSE는 알림 및 상태 업데이트에 이상적입니다. WebSocket과 같이 지속적인 하트비트 패킷 교환이 필요하지 않으며, retry 필드가 재연결 빈도를 제어합니다.

성능 테스트(2024)에 따르면 SSE는 256 바이트 메시지 크기에서 연결당 초당 최대 10,000개의 메시지 스루푸트를 제공합니다. 서버 측에서 각 SSE 연결은 약 5–10 KB의 메모리를 소비하며, 1GB RAM으로 하나의 서버가 50,000개 이상의 동시 연결을 지원할 수 있습니다. 이는 바이너리 프로토콜이 없기 때문에 WebSocket보다 훨씬 적은 양입니다.

Event-stream 형식

text/event-stream 형식은 각 메시지가 줄 바꿈 문자로 구분된 이름이 있는 필드로 구성된 간단한 텍스트 프로토콜입니다. 각 필드는 “필드 이름: 값” 형식입니다. 메시지는 두 개의 줄 바꿈 문자(\n\n)로 구분됩니다.

지원되는 필드: event(이벤트 유형, 기본값 message), data(데이터 문자열, 여러 줄 가능), id(마지막 이벤트 식별자, Last-Event-ID에 저장), retry(재연결 시간(밀리초)). 주석을 콜론(:)으로 시작하고 파서가 무시하지만 하트비트에 사용할 수 있습니다.

필드필수목적
event아니오이벤트 유형(기본 message)
data메시지 데이터 문자열
id아니오Last-Event-ID용 이벤트 식별자
retry아니오재연결 지연(ms)

Event-stream 예시

text
: heartbeat comment
event: update
data: {"user": "Alice", "action": "typing"}
id: 1001

event: notification
data: {"type": "info", "text": "New version available"}
data: {"type": "action", "url": "/upgrade"}
retry: 3000

event: close
data: Session ended

클라이언트의 EventSource API

EventSource API는 SSE를 수신하기 위한 내장 브라우저 인터페이스입니다. 연결을 만들려면 엔드포인트의 URL로 생성자를 호출하면 됩니다. EventSource는 자동으로 연결을 설정하고, 재연결을 처리하고, 수신된 메시지를 JavaScript 이벤트로 파싱합니다.

EventSource 이벤트: open(연결 설정), message(이벤트 지정 없이 메시지 수신), error(연결 오류). 사용자 정의 이벤트(event: custom)의 경우 이벤트 이름으로 addEventListener를 사용할 수 있습니다. EventSource는 재연결 시 자동으로 Last-Event-ID 헤더를 보내어 서버가 중단된 위치부터 스트리머를 재개할 수 있도록 합니다.

MDN 문서(2025)에 따르면 EventSource는 CORS 및 인증 정보 전송(withCredentials)을 지원합니다. 사용자 정의 헤더나 요청 본문을 보내는 데 EventSource는 적합하지 않습니다. fetch + ReadableStream을 통한 수동 구현이 필요합니다. EventSource는 바이너리 데이터를 지원하지 않습니다. 텍스트와 JSON만 가능합니다.

클라이언트 측 JavaScript 코드

js
const eventSource = new EventSource('/api/events/stream');

eventSource.addEventListener('open', () => {
    console.log('SSE 연결이 열림');
});

eventSource.addEventListener('message', (event) => {
    const data = JSON.parse(event.data);
    console.log('수신됨:', data);
    renderUpdate(data);
});

eventSource.addEventListener('notification', (event) => {
    const notification = JSON.parse(event.data);
    showNotification(notification.text);
});

eventSource.addEventListener('error', (error) => {
    console.error('SSE 오류:', error);
    // 브라우저가 자동 재연결함
});

// 연결 닫기
eventSource.close();

SSE vs WebSocket: 비교

SSE와 WebSocket은 실시간 통신을 위한 서로 다른 기술로, 각기 장점이 있습니다. WebSocket은 양방향 데이터 교환(채팅, 게임, 협업 편집)에 적합하고, SSE는 서버에서 클라이언트로의 단방향 스트리머(알림, 뉴스 피드, 티케)에 적합합니다.

주요 차이점은 WebSocket이 HTTP/1.1에서 WebSocket 프로토콜(ws://)로의 업그레이드 요청이 필요하며, 이는 기업 프록시에서 차단될 수 있다는 점입니다. SSE는 일반 HTTP 위에서 작동하며, 어떤 프록시도 통과하고 서버에 특별한 설정이 필요하지 않습니다. SSE는 구현이 더 간단합니다. 서버에 추가 라이브러리가 필요하지 않고 HTTP 응답을 올바르게 구성하면 됩니다.

비교 테스트(2024)에 따르면 단일 서버 프로세스에서 SSE는 간단한 프로토콜 때문에 WebSocket보다 30–50% 더 많은 연결을 지원합니다. 그러나 SSE는 느린 지연 시간(50–200 ms 대 10–50 ms WebSocket)을 가집니다. 이는 SSE가 완전한 양방향 바이너리 프레임이 아닌 청크 HTTP를 사용하기 때문입니다.

특징SSEWebSocket
방향서버 → 클라이언트양방향
프로토콜HTTP (text/event-stream)ws:// / wss:// (RFC 6455)
브라우저97.5% (내장 EventSource)97% (내장 WebSocket)
데이터텍스트 / JSON만텍스트 + 바이너리(Blob, ArrayBuffer)
프록시 처리어떤 프록시도 통과프록시 설정 필요
재연결자동(브라우저)수동 구현
이력Last-Event-ID내장 이력 없음

서버에서 SSE 구현 방법

서버에서 SSE 구현은 라이브러리가 필요하지 않습니다. 올바른 HTTP 헤더를 설정하고 text/event-stream 형식으로 데이터를 보내면 됩니다. 내장된 http 모듈을 사용하는 Node.js의 예를 보어봅시다. 서버는 Content-Type과 Cache-Control 헤더를 설정한 후 N초마다 메시지를 보냅니다.

MDN Web Docs(2025)에 따르면 SSE에 필요한 헤더는 Content-Type: text/event-stream, Cache-Control: no-cache, Connection: keep-alive입니다. Cache-Control이 없으면 브라우저가 SSE 스트리머를 캐시하여 전달이 중단될 수 있습니다. Connection: keep-alive는 브라우저에 연결을 계속 열어 둘 것을 명시적으로 알립니다.

Node.js 서버 코드

js
const http = require('http');

http.createServer((req, res) => {
    res.writeHead(200, {
        'Content-Type': 'text/event-stream',
        'Cache-Control': 'no-cache',
        'Connection': 'keep-alive'
    });

    let eventId = 0;
    const interval = setInterval(() => {
        eventId++;
        res.write(`id: ${eventId}\n`);
        res.write(`event: update\n`);
        res.write(`data: {"time": "${new Date().toISOString()}", "id":${eventId}}\n\n`);
    }, 2000);

    req.on('close', () => {
        clearInterval(interval);
    });
}).listen(3000);

Python(Flask)에서의 SSE

python
from flask import Response, Flask
import time
import json

app = Flask(__name__)

@app.route('/stream')
def stream():
    def generate():
        event_id = 0
        while True:
            event_id += 1
            data = json.dumps(
                {'ticker': 'AAPL', 'price': 150.25})
            yield f'id: {event_id}\nevent: price\ndata: {data}\n\n'
            time.sleep(1)
    return Response(generate(),
        mimetype='text/event-stream')

모바일 앱에서의 SSE

모바일 앱에서 SSE 사용은 iOS 및 Android용 기본 EventSource 구현이 없기 때문에 제한적입니다. 모바일 플랫폼에서 SSE는 제3자 라이브러리를 통해 구현됩니다. iOS에서는 URLSession과 NSURLProtocol을 통해, Android에서는 OkHttp와 SSE 지원(okhttp-sse)을 통해 구현됩니다. React Native와 Flutter용으로 EventSource를 에뮬레이트하는 패키지가 있습니다.

iOS에서 기본 SSE 구현은 URLSessionDataDelegate를 통해 가능합니다. urlSession(_:dataTask:didReceive:)메서드에서 데이터를 수신할 때 앱이 버퍼를 적립하고 event-stream 형식을 수동으로 파싱합니다. iOS 개발 블로그(2024)에 따르면 하트비트 패킷이 없기 때문에 iOS에서 SSE의 배터리 소비는 지속적인 WebSocket 연결보다 40% 낮습니다.

Android에서 OkHttp는 SSE 스트리머를 구독하기 위한 EventSource.Factory 클래스를 제공합니다. Android 앱은 FCM을 사용할 수 없을 때 알림이나 백그라운드 데이터 동기화에 SSE를 사용할 수 있습니다. Android에서 SSE는 장기 지속되는 백그라운드 작업을 위한 WorkManager와 함께 잘 작동합니다. OkHttp 문서(2025)에 따르면 okhttp-sse는 사용자 정의 리스너로 자동 재연결을 지원합니다.

자주 묻는 질문

SSE는 WebSocket과 어떻게 다른가요?

SSE는 HTTP를 통한 단방향 전송(서버 → 클라이언트)으로 클라이언트에 라이브러리가 필요하지 않습니다. WebSocket은 바이너리 프로토콜이 있는 양방향 전송입니다. SSE는 구현이 더 간단하고 WebSocket은 클라이언트도 데이터를 보내는 작업에 적합합니다.

SSE는 바이너리 데이터를 지원하나요?

아니요. SSE는 텍스트 데이터만 전송합니다. 바이너리 데이터(이미지, 음성)에는 Base64 인코딩이 필요하며 크기가 33% 증가합니다. 바이너리 스트리머에는 WebSocket을 사용하는 것이 더 좋습니다.

SSE는 연결 끝김을 어떻게 처리하나요?

EventSource는 연결이 끝깄댐 경우 자동으로 재연결합니다. 지연 시간은 스트리머의 retry 필드(기본 1000 ms)를 통해 설정됩니다. 재연결 시 브라우저는 Last-Event-ID 헤더를 보내어 서버가 중단된 위치부터 스트리머를 재개할 수 있도록 합니다.

브라우저는 몇 개의 SSE 연결을 유지할 수 있나요?

각 브라우저에는 하나의 도메인에 대한 동시 HTTP 연결 수에 제한이 있습니다. HTTP/1.1의 경우 도메인당 6–8 연결, HTTP/2의 경우 가지 100개입니다. SSE는 하나의 연결을 사용하므로 다른 요청과 경합하지 않습니다.

SSE를 채팅에 사용할 수 있나요?

SSE는 메시지 수신(입력)에만 적합합니다. 메시지 전송(출력)에는 별도의 HTTP 요청(POST)이 필요합니다. 완전한 채팅에는 하나의 연결에서 양방향 통신을 제공하는 WebSocket이나 Socket.IO를 사용하는 것이 더 편리합니다.

요약

  • SSE는 추가 라이브러리 없이 일반 HTTP 연결을 통한 서버에서 클라이언트로의 단방향 데이터 전송에 대한 표준입니다.
  • EventSource API는 97.5% 현대 브라우저가 지원하는 내장 브라우저 인터페이스입니다.
  • 간단한 텍스트 프로토콜 text/event-stream에는 event, data, id, retry 필드가 있습니다.
  • 자동 재연결 — Last-Event-ID를 지원하여 중단된 위치부터 스트리머를 재개합니다.
  • 효율성 — SSE는 간단한 프로토콜 때문에 WebSocket보다 더 많은 서버 연결(50,000+)을 지원합니다.
  • 모바일 플랫폼에서 SSE는 수동 스트리머 파싱과 함께 OkHttp(Android) 또는 URLSession(iOS)을 통해 구현됩니다.
  • 단방향 스트리머(알림, 피드, 티케)에는 SSE를, 양방향 통신에는 WebSocket 또는 Socket.IO를 선택하십시오.

턴키 방식의 모바일 애플리케이션을 개발해 드립니다

IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.

프로젝트 논의

더 읽어보기