[Node.js] Server Sent Events

Main·2024년 10월 8일
0

Node.js

목록 보기
17/20
post-thumbnail

Server Sent Events(SSE) ?

Server-Sent Events (SSE)는 서버에서 클라이언트(주로 웹 브라우저)로 일방적으로 데이터를 지속적으로 보내는 방식입니다. 이 기술을 사용하면 서버는 클라이언트의 요청 없이도 실시간으로 데이터를 전송할 수 있어, 실시간 업데이트가 필요한 애플리케이션에 적합합니다.

기존에는 서버의 변경된 데이터를 가져오기 위해서 페이지 새로고침, 지속적으로 request를 보내는 폴링, 외부 플러그인 이용 등을 사용해야 했습니다. 이외에도 websocket을 사용할 수 있지만 HTTP 통신을 이용하는 것이 아닌 웹소켓만을 위한 별도의 서버와 프로토콜로 통신하기 때문에 구현하는비용이 많이 든다는 단점이 있습니다. 하지만 SSE는 기존 HTTP 웹 서버에서 HTTP API 만으로 동작되며 구현도 간단하기 때문에 서버와 프론트엔드 양측 모두 매우 쉽게 개발이 가능합니다.


Server Sent Events와 Polling, WebSocket의 차이점

1 ) Server Sent events vs Polling

폴링(Polling)은 클라이언트가 일정한 주기로 서버에 데이터를 요청하는 방식입니다. 즉, 클라이언트는 정해진 간격으로 서버에 HTTP 요청을 보내고 서버는 그에 대한 응답을 반환합니다.

폴링은 클라이언트가 서버에 주기적으로 요청을 보내는 방식이고, SSE는 서버가 클라이언트에 필요한 데이터를 자동으로 푸시하는 방식입니다. SSE는 서버 측 이벤트 발생 시 바로 데이터를 전송하기 때문에 폴링보다 실시간성이 뛰어납니다.

2 ) Server Sent evnets vs WebSocket

웹소켓(WebSocket)양방향 통신을 지원하는 프로토콜입니다. 클라이언트와 서버 간의 지속적인 연결을 유지하고, 양쪽 모두 자유롭게 데이터를 주고받을 수 있습니다. HTTP는 주로 요청-응답 기반으로 통신이 이루어지지만, 웹소켓은 연결을 한 번 맺으면 서버와 클라이언트 간에 실시간으로 데이터 교환이 가능합니다.

웹소켓은 클라이언트와 서버가 양방향으로 데이터를 주고받을 수 있지만, SSE는 서버에서 클라이언트로 일방향으로 데이터가 전송됩니다.

웹소켓은 양방향 통신을 위한 프로토콜 설정과 관리가 복잡한 반면, SSE는 더 간단한 설정으로도 실시간 데이터를 서버에서 클라이언트로 푸시할 수 있습니다.

웹소켓은 채팅 애플리케이션, 게임 등 양방향 실시간 통신이 필요한 경우 적합하고, SSE는 주식 시세나 뉴스 알림처럼 서버에서 클라이언트로의 일방향 업데이트가 필요한 경우 더 적합합니다.

기술통신 방향브라우저 지원실시간성데이터 형태자동 재접속최대 동시 접속 수프로토콜
폴링단방향모든 브라우저에서 지원낮음UTF-8No브라우저 한도 없음, 요청 수에 따라 서버 부하 증가HTTP
웹소켓양방향대부분 브라우저 지원매우 높음Binary, UTF-8No서버 셋업에 따라 다름, 브라우저 연결 한도 없음WebSocket
SSE단방향대부분 모던 브라우저 지원
(pollyfills 가능)높음UTF-8Yes (3초마다)HTTP에서는 브라우저당 6개 연결, HTTP/2로는 100개 기본 지원HTTP

Server Sent Events의 특징

  • 단방향 통신: 서버가 클라이언트에 데이터를 푸시하는 방식입니다. 클라이언트는 한 번 연결된 후 서버로부터 지속적인 업데이트를 받을 수 있습니다.
  • 텍스트 기반 프로토콜: 서버는 text/event-stream MIME 타입을 사용해 이벤트를 전송하며, 이는 텍스트 기반입니다.
  • 간단한 구현: WebSocket처럼 양방향 통신을 지원하는 다른 기술에 비해 구현이 더 간단합니다.
  • 브라우저 지원: 대부분의 최신 브라우저가 SSE를 기본적으로 지원합니다.
  • HTTP 기반 : Connection 유지를 위해 HTTP protocol 을 사용, HTTP/2를 통한 multiplexing 사용 가능

Server Sent Events의 장점

  • 간단한 구현: WebSocket에 비해 설정이 단순하며 서버와 클라이언트 간의 통신이 매우 쉽게 이루어집니다.
  • 자동 재연결: 연결이 끊어지면 클라이언트가 자동으로 재연결을 시도합니다.
  • 양방향 통신이 필요 없는 경우: 단순히 서버에서 클라이언트로 데이터를 푸시하는 경우 적합합니다.

Server Sent Events의 단점

  • 단방향 통신: 클라이언트에서 서버로 메시지를 보내는 기능은 없습니다. 따라서 양방향 통신이 필요한 경우에는 WebSocket을 사용하는 것이 더 적합합니다.
  • HTTP 기반: HTTP/2를 사용하지 않으면 각 연결마다 새로운 요청이 필요하므로, 대규모 실시간 통신에 적합하지 않을 수 있습니다.

Server Sent Events 사용이 적합한 경우

  • 실시간 업데이트가 필요한 경우
    • 서버에서 발생하는 이벤트를 클라이언트에 실시간으로 알리는 것이 중요한 애플리케이션에 적합합니다.
    • 예시: 주식 시세, 날씨 업데이트, 뉴스 피드, 스포츠 경기 결과와 같은 실시간 정보를 제공하는 서비스.
  • 빈번한 데이터 푸시가 필요한 경우
    • 서버에서 데이터가 자주 업데이트되고, 이를 클라이언트에게 즉각적으로 전달해야 할 때 유용합니다.
    • 예시: 대시보드, 실시간 로그 모니터링, 실시간 분석 시스템.
  • 알림 시스템
    • 서버에서 발생하는 특정 이벤트(알림, 메시지 등)를 실시간으로 클라이언트에 푸시할 때 SSE를 사용할 수 있습니다.
    • 예시: 채팅 시스템에서 새 메시지가 올 때 사용자에게 알림을 푸시하는 경우.
  • 단방향 통신이 충분한 경우
    • 클라이언트가 서버로 응답을 보낼 필요가 없는, 단방향 통신이 충분한 상황에서 SSE가 적합합니다.
    • 예시: 클라이언트에서 서버의 상태 변화를 관찰하는 대시보드와 같이 서버가 주기적으로 데이터를 전송하는 경우.
  • 양방향 통신이 필요하지 않을 때
    • 웹소켓과 달리, SSE는 서버에서 클라이언트로의 일방향 데이터 전송을 효율적으로 처리합니다. 클라이언트에서 서버로의 응답이 필요 없는 애플리케이션에서는 WebSocket보다 SSE가 더 적합할 수 있습니다.
    • 예시: 채팅 앱에서 메시지 전송 자체는 클라이언트에서 서버로의 요청이 있지만, 채팅 메시지 수신은 서버에서 클라이언트로 일방적으로 전달되는 경우.
  • 간단한 실시간 통신 구현이 필요한 경우
    • SSE는 WebSocket과 달리 상대적으로 간단한 설정으로 실시간 통신을 구현할 수 있습니다. 특히, 양방향 통신이 필요 없고 자동 재연결 기능이 유용한 경우에 적합합니다.
    • 예시: 실시간 주식 차트나 실시간 서버 상태 모니터링 애플리케이션.

Server Sent Event 사용이 적합하지 않은 경우

  • 양방향 통신이 필요한 경우
    • 클라이언트와 서버 간의 양방향 데이터 교환이 필요한 경우에는 SSE 대신 WebSocket이 적합합니다. 예를 들어, 실시간 채팅이나 게임과 같이 양쪽에서 데이터를 주고받아야 하는 경우에는 WebSocket이 더 나은 선택입니다.
  • 브라우저 호환성 문제가 중요한 경우
    • SSE는 대부분의 최신 브라우저에서 지원되지만, 오래된 브라우저나 특정 환경에서는 지원되지 않을 수 있습니다. 이런 경우 폴링이나 WebSocket 같은 대안이 필요할 수 있습니다.
  • 규모가 매우 큰 실시간 시스템
    • 수많은 클라이언트가 연결된 환경에서는 SSE가 HTTP 연결을 계속 유지해야 하기 때문에 서버에 부담을 줄 수 있습니다. 대규모 실시간 시스템에서 성능 최적화가 중요한 경우, WebSocket이나 다른 기술을 사용하는 것이 적합할 수 있습니다.

Server Sent Events 사용하기

서버 코드

// server/app.js

const express = require('express'); // Express 모듈을 불러옵니다.
const app = express(); // Express 애플리케이션을 생성합니다.

app.get('/events', (req, res) => {
  // SSE(Server-Sent Events) 엔드포인트 설정
  // 응답 헤더 설정: SSE는 스트리밍 방식이므로 Content-Type을 'text/event-stream'으로 설정
  res.setHeader('Content-Type', 'text/event-stream');
  // 브라우저나 중간 캐싱을 방지하기 위해 Cache-Control을 'no-cache'로 설정
  res.setHeader('Cache-Control', 'no-cache');
  // 연결을 유지하도록 Connection을 'keep-alive'로 설정
  res.setHeader('Connection', 'keep-alive');
  // CORS(Cross-Origin Resource Sharing)를 허용하기 위한 헤더 설정 (모든 출처 허용)
  res.setHeader('Access-Control-Allow-Origin', '*');

  // 5초마다 클라이언트에 메시지를 전송하는 인터벌 설정
  const intervalId = setInterval(() => {
    // 현재 시간을 'data' 필드로 보내는 SSE 메시지 작성 및 전송
    res.write(`data: ${new Date().toLocaleTimeString()}\n\n`);
  }, 5000);

  // 클라이언트가 연결을 끊으면 인터벌을 제거하여 서버 자원 낭비 방지
  req.on('close', () => {
    clearInterval(intervalId); // 클라이언트가 연결을 닫으면 인터벌 중지
  });
});

// 서버를 8080번 포트에서 실행
app.listen(8080, () => {
  console.log('Server is running on port 8080');
});

클라이언트 코드

// client/index.html

<!DOCTYPE html>
<html>
  <body>
    <h1>Server-Sent Events</h1>
    <!-- 실시간으로 서버에서 전송되는 데이터를 표시할 영역 -->
    <div id="result"></div>

    <script>
      // EventSource 객체를 생성하고, 서버의 '/events' 엔드포인트에 연결
      const eventSource = new EventSource('http://localhost:8080/events');

      // 서버에서 메시지가 수신될 때마다 실행되는 이벤트 핸들러
      eventSource.onmessage = function(event) {
        // 수신된 데이터를 <div id="result"> 영역에 추가
        document.getElementById('result').innerHTML += event.data + '<br>';
      };
    </script>
  </body>
</html>

동작 방식

  • 클라이언트가 /events 경로로 요청을 보냅니다.
  • 서버는 응답의 Content-Type을 text/event-stream으로 설정하고, 5초마다 클라이언트에 현재 시간을 이벤트로 전송합니다.
  • 클라이언트는 EventSource 객체를 사용하여 서버로부터 오는 데이터를 지속적으로 받습니다.

참고 사이트

https://inpa.tistory.com/entry/NODE-📚-Server-Sent-Events-💯-정리-사용법

profile
함께 개선하는 프론트엔드 개발자

0개의 댓글