React Native에서 react-native-sse를 활용한 실시간 스트리밍 구현

라이브러리 설치

React Native 환경에서 Server-Sent Events(SSE)를 처리하기 위해 react-native-sse 패키지를 사용합니다. 이 라이브러리는 웹 브라우저의 표준 EventSource API를 모방하여 네이티브 앱에서도 스트리밍 데이터를 손쉽게 수신할 수 있도록 지원합니다.

npm install react-native-sse

SSE 연결 및 이벤트 처리 기본 구조

모듈을 불러온 후, SSE 서버의 URL을 인자로 전달하여 인스턴스를 생성합니다. 이어서 open, , error, close 이벤트에 대한 리스너를 등록하여 연결 상태를 관리합니다.

import EventSource from 'react-native-sse';

const url = 'https://example.com/stream-endpoint';
const eventSource = new EventSource(url);

// 연결 성공 시
eventSource.addEventListener('open', (e) => {
  console.log('SSE 연결이 수립되었습니다.');
});

// 메시지 수신 시
eventSource.addEventListener('message', (e) => {
  console.log('수신된 데이터:', e.data);
});

// 에러 발생 시
eventSource.addEventListener('error', (e) => {
  if (e.type === 'error') {
    console.error('네트워크 오류 발생:', e.message);
  } else if (e.type === 'exception') {
    console.error('예외 발생:', e.error);
  }
});

// 연결 종료 시
eventSource.addEventListener('close', (e) => {
  console.log('SSE 연결이 해제되었습니다.');
});

상세 설정 및 옵션

EventSource 생성자의 두 번째 인자를 통해 요청 방식, 헤더, 타임아웃 등 다양한 옵션을 구성할 수 있습니다. 특히 인증이 필요한 API나 POST 방식의 요청을 보낼 때 유용합니다.

const configOptions = {
  method: 'GET',             // HTTP 요청 방식 (기본값: GET)
  headers: {
    'Authorization': 'Bearer YOUR_TOKEN'
  },
  body: undefined,           // 요청 본문 (POST 요청 시 사용)
  timeout: 0,                // 연결 유지 시간 (0은 무제한)
  pollingInterval: 5000,     // 재연결 시도 간격 (ms)
  withCredentials: false,    // CORS 요청 시 쿠키 포함 여부
  debug: false,              // 디버깅 로그 활성화
};

const source = new EventSource(url, configOptions);

실전 예제: OpenAI API 스트리밍 채팅

OpenAI의 Chat Completion API는 스트리밍 응답을 지원합니다. react-native-sse를 사용하여 실시간으로 들어오는 토큰을 화면에 표시하는 컴포넌트 예제입니다.

import React, { useEffect, useState } from 'react';
import { View, Text, StyleSheet } from 'react-native';
import EventSource from 'react-native-sse';

const OPENAI_API_KEY = 'YOUR_OPENAI_API_KEY';

const ChatStreamScreen = () => {
  const [responseText, setResponseText] = useState('응답 대기 중...');

  useEffect(() => {
    const apiUrl = 'https://api.openai.com/v1/chat/completions';
    
    // 요청 본문 구성
    const requestBody = JSON.stringify({
      model: 'gpt-3.5-turbo',
      messages: [{ role: 'user', content: 'React Native에 대해 간단히 설명해줘.' }],
      stream: true, // 스트리밍 모드 활성화
    });

    const sseConnection = new EventSource(apiUrl, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${OPENAI_API_KEY}`,
      },
      body: requestBody,
      pollingInterval: 0, // 수동 종료 시 재연결 방지
    });

    sseConnection.addEventListener('open', () => {
      setResponseText(''); // 텍스트 초기화
    });

    sseConnection.addEventListener('message', (event) => {
      if (event.data === '[DONE]') {
        sseConnection.close();
        return;
      }

      try {
        const parsedData = JSON.parse(event.data);
        const contentChunk = parsedData.choices?.[0]?.delta?.content;
        
        if (contentChunk) {
          setResponseText((prev) => prev + contentChunk);
        }
      } catch (err) {
        console.warn('데이터 파싱 오류');
      }
    });

    sseConnection.addEventListener('error', (err) => {
      console.error('스트리밍 에러:', err);
    });

    // 컴포넌트 언마운트 시 연결 정리
    return () => {
      sseConnection.removeAllEventListeners();
      sseConnection.close();
    };
  }, []);

  return (
    <View style={styles.container}>
      <Text style={styles.textStyle}>{responseText}</Text>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    padding: 20,
  },
  textStyle: {
    fontSize: 16,
    lineHeight: 24,
  },
});

export default ChatStreamScreen;

태그: React Native SSE react-native-sse streaming OpenAI API

8월 19일 17:54에 게시됨