Server-Sent Events란?
HTML5가 등장하기 전까지는 HTML에 서버 푸시를 위한 표준화된 기술이 없었기 때문에 웹에서 실시간 정보를 받아와야 할 때 외부 플러그인을 이용하거나 서버 푸시를 흉내 낸 Ajax 폴링(polling) 기법 등을 사용했습니다. 하지만 플러그인 종속적인 웹은 해당 플러그인을 설치해야 한다는 불편함이 있으며 폴링처럼 주기적인 요청을 통한 구현은 쓸모없는 요청의 발생으로 인한 대역폭의 낭비가 불가피하였습니다. HTML5의 Server-Sent Events(이하 SSE)는 이러한 문제 없이 서버가 필요할 때마다 클라이언트에게 데이터를 줄 수 있게 해주는 서버 푸시 기술입니다.
SSE의 장점
SSE의 장점으로는 다음과 같은 것들이 있습니다.
- 전통적인 HTTP를 통해 통신하므로 다른 프로토콜이 필요가 없습니다.
- 재접속 처리 같은 대부분의 저수준 처리가 자동으로 됩니다.
- 표준 기술답게 IE를 제외한 브라우저 대부분을 지원합니다.
- HTML과 JavaScript만으로 구현할 수 있으므로 현재 지원되지 않는 브라우저(IE 포함)도 polyfill을 이용해 크로스 브라우징이 가능합니다. (여기서 polyfill이란 브라우저가 지원하지 않는 API를 플러그인이나 JavaScript 등으로 흉내 내 구현한 것을 뜻합니다. polyfill에 대한 자세한 설명은 이 블로그 포스트를 참조하시기 바랍니다.)
사실 종합해보면 SSE의 모든 장점은 간편함으로 요약할 수 있습니다.
적용 예
위의 SSE의 장점에서 보듯이 SSE는 구현이 아주 간편합니다. 클라이언트는 서버로부터 스트림을 받아 EventSource
객체를 통해 서버가 푸시하는 데이터를 받아 처리하기만 하면 됩니다.
먼저 클라이언트 측의 코드입니다.
var es = new EventSource(stream_url);
es.onmessage = function (event) {
// 이벤트 설정이안된 기본 데이터 처리
};
es.addEventListener('myevent', function(e) {
// 'myevent' 이벤트의 데이터 처리
}, false);
EventSource
객체의 속성은 다음과 같습니다.
onmessage
- 기본 메시지가 왔을 때 호출
onopen
- 접속이 맺어졌을 때 호출
onerror
- 오류 발생 시 호출
EventSource
의 addEventListener()
를 사용하면 위 3개의 이벤트뿐만 아니라 따로 지정된 이벤트의 데이터도 받아 처리할 수 있습니다.
자 그럼 Flask와 Redis를 이용한 서버 측의 코드를 볼까요? (예제는 Redis를 이용하였지만, Publish/Subscribe Model이라면 다른 걸 쓰셔도 무방합니다.)
def event_stream():
pub = redis.pubsub()
pub.subscribe('sse_example_channel')
for msg in pub.listen():
if msg['type'] != 'subscribe':
event, data = json.loads(msg['data'])
yield u'event: {0}\ndata: {1}\n\n'.format(event, data)
else:
yield u'data: {0}\n\n'.format(msg['data'])
@app.route('/stream')
def get_pushes():
return Response(event_stream(), mimetype="text/event-stream")
@app.route('/post')
def publish_data():
# ...
redis.publish('sse_example_channel', json.dumps([event, data]))
응답의 형식을 text/event-stream
으로 주고 이벤트 스트림을 걸어 놓습니다. event_stream()
에서는 새로운 데이터가 들어오면 데이터를 형식에 맞추어 푸시하고 있습니다. SSE에서의 데이터 형식은 2개의 개행으로 구분됩니다.
data: This is the first message.
data: This is the second message, it
data: has two lines.
event: myevent
data: This is the third message with a separated event.
WebSocket과 Server-Sent Events
완전한 양방향 통신을 지원하는 WebSocket이 SSE보다 더 매력적으로 보일 수 있습니다. WebSocket 또한 표준 기술인데다 양방향 통신이고 브라우저 지원 범위도 더 넓습니다.
그렇지만 WebSocket이 SSE보다 항상 더 좋은 것은 아닙니다. 채팅이나 게임 같이 사용자가 서버의 데이터에 즉각 반응해야 하는 경우라면 WebSocket을 사용하는 것이 더 효율적이겠지만 많은 경우 클라이언트 측에서의 반응은 필요가 없습니다. 주식차트, 뉴스피드, 푸시 노티피케이션 등이 대표적인 예입니다.
브라우저 지원 부분에서도 SSE가 더 유리한 측면이 있습니다. WebSocket은 브라우저가 지원하지 않을 때에는 서버 측에서 이에 대응하는 fallback 프로토콜을 별도로 구현해야만 합니다. 반면, SSE는 클라이언트 기술이기 때문에 서버 측 구현을 더 복잡하게 하지 않고도 브라우저가 JavaScript만 지원한다면 polyfill을 이용하여 구현이 가능합니다.
따라서 상황에 따라 복잡한 WebSocket을 이용하는 것보다는 간단한 SSE를 통해 구현하는 것이 여러 가지로 유리할 수 있습니다.
스포카에서는 “식자재 시장을 디지털화한다” 라는 슬로건 아래, 매장과 식자재 유통사에 도움되는 여러 솔루션들을 개발하고 있습니다.
더 나은 제품으로 세상을 바꾸는 성장의 과정에 동참 하실 분들은 채용 정보 페이지를 확인해주세요!