메인 콘텐츠로 건너뛰기
Sonamu는 fastify-sse-v2 플러그인을 기반으로 **Server-Sent Events (SSE)**를 지원합니다. SSE를 사용하면 서버에서 클라이언트로 실시간 데이터를 푸시할 수 있습니다.

SSE란?

Server-Sent Events는 서버에서 클라이언트로 단방향 실시간 통신을 제공하는 기술입니다.

HTTP vs SSE vs WebSocket

비교표

특징HTTPSSEWebSocket
방향요청→응답서버→클라이언트양방향
프로토콜HTTPHTTPWebSocket
재연결X자동수동
복잡도낮음중간높음
용도일반 API실시간 푸시실시간 채팅

SSE 사용 사례

실시간 알림

새 메시지, 좋아요, 댓글 등

진행 상황

파일 업로드, 작업 처리 진행률

라이브 피드

뉴스 피드, 소셜 미디어 업데이트

모니터링

서버 상태, 로그 스트리밍

기본 설정

sonamu.config.ts

import { type SonamuConfig } from "sonamu";

export const config: SonamuConfig = {
  server: {
    plugins: {
      sse: true,  // SSE 플러그인 활성화
    }
  }
};
기본 동작:
  • SSE 엔드포인트 자동 등록
  • 자동 재연결 지원
  • Keep-alive 자동 전송

SSE 플러그인 옵션

간단한 활성화/비활성화
plugins: {
  sse: true,   // 활성화
  sse: false,  // 비활성화
}

SSE 작동 방식

연결 흐름

HTTP 헤더

SSE는 특수한 HTTP 헤더를 사용합니다:
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive
특징:
  • text/event-stream: SSE 전용 Content-Type
  • no-cache: 캐싱 방지
  • keep-alive: 연결 유지

실전 설정 예제

1. 기본 설정 (권장)

export const config: SonamuConfig = {
  server: {
    plugins: {
      sse: true,  // 간단하게 활성화
    }
  }
};

2. 개발/프로덕션 분리

const isDevelopment = process.env.NODE_ENV === 'development';

export const config: SonamuConfig = {
  server: {
    plugins: {
      sse: !isDevelopment,  // 프로덕션에서만 활성화
    }
  }
};
이유: 개발 환경에서는 HMR로 인해 연결이 자주 끊김

3. 조건부 활성화

export const config: SonamuConfig = {
  server: {
    plugins: {
      sse: process.env.ENABLE_SSE === 'true',
    }
  }
};
ENABLE_SSE=true

압축 비활성화

SSE는 스트리밍 응답이므로 압축을 비활성화해야 합니다.
export const config: SonamuConfig = {
  server: {
    plugins: {
      sse: true,
      compress: {
        global: true,  // 전역 압축 활성화
        threshold: 1024,
        encodings: ["gzip"],
      }
    }
  }
};
@stream 데코레이터에서 자동 처리:
@stream({
  type: 'sse',
  events: z.object({
    message: z.string(),
  })
})
@api({
  compress: false,  // 자동으로 압축 비활성화 (권장)
})
async *streamUpdates() {
  // ...
}

CORS 설정

SSE를 다른 도메인에서 사용하려면 CORS 설정이 필요합니다.
export const config: SonamuConfig = {
  server: {
    plugins: {
      sse: true,
      cors: {
        origin: ['https://example.com', 'https://app.example.com'],
        credentials: true,
      }
    }
  }
};
주의: SSE는 인증 쿠키 등을 전송할 수 있으므로 credentials: true 설정 필요

환경별 전략

개발 환경

export const config: SonamuConfig = {
  server: {
    plugins: {
      sse: true,
      cors: {
        origin: 'http://localhost:5173',  // Vite 개발 서버
        credentials: true,
      }
    }
  }
};

프로덕션 환경

export const config: SonamuConfig = {
  server: {
    plugins: {
      sse: true,
      cors: {
        origin: process.env.FRONTEND_URL,
        credentials: true,
      }
    }
  }
};
FRONTEND_URL=https://app.example.com

타임아웃 설정

SSE 연결은 장시간 유지되므로 타임아웃 설정이 중요합니다.
export const config: SonamuConfig = {
  server: {
    fastify: {
      connectionTimeout: 0,  // 타임아웃 비활성화
      keepAliveTimeout: 5000,  // Keep-alive: 5초
    },
    plugins: {
      sse: true,
    }
  }
};
설정 값:
  • connectionTimeout: 0: 연결 타임아웃 비활성화 (SSE는 장시간 유지)
  • keepAliveTimeout: Keep-alive 간격 (기본값: 5초)

프록시 설정 (Nginx)

Nginx를 사용하는 경우 SSE를 위한 설정이 필요합니다.
server {
    listen 80;
    server_name api.example.com;

    location /stream/ {
        proxy_pass http://localhost:3000;
        
        # SSE 필수 설정
        proxy_set_header Connection '';
        proxy_http_version 1.1;
        chunked_transfer_encoding off;
        
        # 버퍼링 비활성화
        proxy_buffering off;
        proxy_cache off;
        
        # 타임아웃
        proxy_read_timeout 24h;
        proxy_send_timeout 24h;
    }
}
핵심 설정:
  • proxy_buffering off: 버퍼링 비활성화 (즉시 전송)
  • proxy_cache off: 캐싱 비활성화
  • proxy_read_timeout 24h: 읽기 타임아웃 (장시간)

디버깅

브라우저 개발자 도구

Network 탭 → 스트림 요청 선택 → Headers 탭

Request Headers:
  Accept: text/event-stream
  
Response Headers:
  Content-Type: text/event-stream
  Cache-Control: no-cache
  Connection: keep-alive

EventStream 탭:
  event: message
  data: {"text": "Hello"}
  
  event: update
  data: {"count": 5}

curl 테스트

# SSE 연결 테스트
curl -N http://localhost:3000/stream/updates

# 결과:
# event: message
# data: {"text": "Hello"}
#
# event: update
# data: {"count": 5}
#
# event: end
# data: END
옵션:
  • -N: 버퍼링 비활성화 (즉시 출력)

주의사항

SSE 설정 시 주의사항:
  1. 압축 비활성화: SSE는 스트리밍이므로 압축 금지
    @api({ compress: false })
    async *streamData() { ... }
    
  2. 타임아웃 설정: 장시간 연결 유지
    fastify: {
      connectionTimeout: 0,
    }
    
  3. CORS 설정: 다른 도메인에서 사용 시 필요
    cors: {
      origin: 'https://example.com',
      credentials: true,
    }
    
  4. 재연결 처리: 클라이언트는 자동 재연결 구현 필요
    // EventSource가 자동으로 처리
    const source = new EventSource('/stream/updates');
    
  5. 브라우저 제한: 동시 SSE 연결 수 제한 (도메인당 6개)
    • 해결: HTTP/2 사용 또는 연결 재사용
  6. 프록시 버퍼링: Nginx 등 버퍼링 비활성화 필요
    proxy_buffering off;
    

브라우저 지원

SSE는 모든 모던 브라우저에서 지원됩니다:
브라우저지원
Chrome
Firefox
Safari
Edge
IE 11❌ (polyfill 필요)
IE 11 지원: event-source-polyfill

다음 단계