반응형
🚀 Server-Sent Events(SSE) 완전 가이드
웹 애플리케이션에서 서버가 실시간으로 클라이언트에 이벤트를 푸시(push)해야 할 때, Server-Sent Events(SSE)가 간단하면서도 효율적인 솔루션이 됩니다. 오늘은 SSE의 개념, 작동 방식, 브라우저 지원, 구현 예제, 주의사항까지 블로그 글 형태로 자세히 알아보겠습니다.
1. SSE란 무엇인가?
Server-Sent Events(SSE)는 HTML5에서 도입된 기술로, 클라이언트가 HTTP 연결을 열어두면 서버가 이 연결을 통해 텍스트 기반 이벤트 스트림을 지속적으로 전송할 수 있게 합니다.
- 단방향 스트리밍: 서버 → 클라이언트
- 텍스트 기반: 간단한 텍스트 프로토콜로 메시지 전송
- 자동 재연결: 네트워크 오류 시 자동으로 재접속 시도
2. 왜 SSE를 사용하나?
간편한 구현
- HTTP 표준을 따르므로 별도의 WebSocket 핸드셰이크가 필요 없습니다.
- API도 매우 단순해 클라이언트와 서버 코드를 몇 줄만 작성하면 됩니다.
브라우저 내장 지원
- `` 태그 하나로 바로 사용 가능.
- EventSource 인터페이스 제공.
자동 재연결 & 메시지 ID 관리
- 네트워크 끊김 시 자동으로 재접속을 시도합니다.
- 마지막으로 받은 이벤트 ID를 서버에 전달해 중복 없는 메시지 수신 보장.
낮은 오버헤드
- 텍스트 스트림을 사용해 메시지 헤더/푸터가 WebSocket보다 가볍습니다.
3. SSE 동작 원리
- 클라이언트가
EventSource객체 생성 - 브라우저가 서버에 HTTP GET 요청(특수 헤더 포함)
- 서버는
Content-Type: text/event-stream헤더와 함께 텍스트 스트림 전송 - 클라이언트는 스트림을 파싱해
message,event,id,retry필드 처리 - 연결이 끊기면 클라이언트는
retry값(또는 기본 3초) 후 재접속 시도
4. 브라우저 지원 현황
- Chrome, Firefox, Safari, Edge(Chromium) 모두 지원
- IE는 지원하지 않음(폴리필 필수)
5. 클라이언트 구현 예제
// 클라이언트 코드 (JavaScript)
const evtSource = new EventSource('/sse-stream');
// 기본 메시지 수신
evtSource.onmessage = (event) => {
console.log('메시지:', event.data);
display(event.data);
};
// 커스텀 이벤트 수신
evtSource.addEventListener('customEvent', (event) => {
console.log('customEvent:', event.data);
handleCustom(JSON.parse(event.data));
});
// 오류 처리 및 재연결
evtSource.onerror = (err) => {
if (evtSource.readyState === EventSource.CLOSED) {
console.error('연결이 닫혔습니다.');
} else {
console.error('일시적 오류, 재연결 시도 중...', err);
}
};
6. 서버 구현 예제
Node.js + Express
const express = require('express');
const app = express();
app.get('/sse-stream', (req, res) => {
res.set({
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
Connection: 'keep-alive'
});
res.flushHeaders();
let id = 0;
const sendEvent = () => {
id++;
res.write(`id: ${id}\n`);
res.write(`event: message\n`);
res.write(`data: 안녕하세요! 현재 서버 시간은 ${new Date().toLocaleTimeString()} 입니다.\n\n`);
};
// 5초마다 이벤트 전송
const interval = setInterval(sendEvent, 5000);
// 클라이언트 연결 해제 시 정리
req.on('close', () => {
clearInterval(interval);
res.end();
});
});
app.listen(3000, () => {
console.log('SSE 서버가 http://localhost:3000 에서 실행 중...');
});
Python + Flask
from flask import Flask, Response
import time
app = Flask(__name__)
@app.route('/sse-stream')
def sse_stream():
def generate():
id = 0
while True:
id += 1
yield f"id: {id}\n"
yield "event: message\n"
yield f"data: 서버 시간이 {time.strftime('%H:%M:%S')} 입니다.\n\n"
time.sleep(5)
return Response(generate(), mimetype='text/event-stream')
if __name__ == '__main__':
app.run(port=5000, threaded=True)
7. 주요 필드 설명
id: 마지막으로 받은 메시지 ID. 클라이언트 재접속 시Last-Event-ID헤더로 서버에 전달event: 이벤트 이름.addEventListener로 개별 처리 가능data: 실제 메시지 내용. 여러 줄 지원(각 줄 앞에data:)retry: 재접속 대기 시간(ms). 서버에서 동적 설정 가능
retry: 10000 // 클라이언트는 10초 후 재접속 시도
8. 주의사항 & 베스트 프랙티스
Keep-Alive 설정
- 프록시나 로드밸런서가 연결을 자동 종료하지 않도록
Connection: keep-alive및 적절한 간격으로 빈 줄 전송
- 프록시나 로드밸런서가 연결을 자동 종료하지 않도록
데이터 크기 주의
- 대용량 메시지는 스트림 처리 성능에 영향. 필요 시 차분(diff) 데이터 전송
폴리필 사용
- Internet Explorer 및 일부 구형 브라우저 대응을 위해 EventSource 폴리필 사용
동시 연결 제한
- 브라우저마다 도메인당 연결 수 제한이 있으므로, 너무 많은 SSE 연결 생성하지 않도록 관리
보안
- HTTPS 사용 권장
- 인증이 필요한 경우, 토큰 기반 인증 또는 세션 쿠키 활용
9. 결론
Server-Sent Events는 단순성, 브라우저 내장 지원, 자동 재연결 등 장점을 가진 효율적인 서버 → 클라이언트 푸시 솔루션입니다. WebSocket 같은 복잡한 양방향 통신이 필요하지 않은 경우, SSE를 도입해 개발 생산성을 높이고 서버 부하를 낮춰보세요!
반응형
'기타' 카테고리의 다른 글
| Android Studio에서 SDK 설치 절차 (14) | 2025.08.21 |
|---|---|
| 안드로이드 스튜디오로 시작하는 앱 개발 (9) | 2025.08.20 |
| CORS(교차 출처 리소스 공유, Cross-Origin Resource Sharing) (9) | 2025.08.17 |
| TaskMaster CLI 마스터하기: 실전 팁과 트러블슈팅 (13) | 2025.08.13 |
| 생산성 극대화: TaskMaster CLI 고급 활용법 (12) | 2025.08.12 |