요약
HTTP를 통해 API 응답을 스트리밍하려면 서버 전송 이벤트(SSE)를 사용하세요. Content-Type: text/event-stream을 보내고, 이벤트를 data: {json}\n\n 형식으로 작성합니다. SSE는 AI 응답 스트리밍, 진행 상황 업데이트 및 실시간 피드에 유용합니다. Modern PetstoreAPI는 AI 반려동물 추천 및 주문 상태 업데이트에 SSE를 사용합니다.
서론
귀사의 API는 반려동물에 대한 AI 추천을 생성합니다. 응답에는 10초가 걸립니다. 사용자들을 기다리게 하시겠습니까, 아니면 결과가 생성되는 즉시 스트리밍하시겠습니까?
서버 전송 이벤트(SSE)를 사용하면 응답을 실시간으로 스트리밍할 수 있습니다. AI가 결과를 생성하는 즉시 사용자들은 이를 확인하여 더 나은 경험을 할 수 있습니다.
Modern PetstoreAPI는 AI 반려동물 추천, 주문 상태 업데이트, 재고 변경에 SSE를 사용합니다.
스트리밍 API를 테스트하는 경우, Apidog은 SSE 테스트 및 검증을 지원합니다.
SSE 기본 사항
SSE는 서버에서 클라이언트로의 HTTP 기반 단방향 스트리밍입니다.
SSE 형식
Content-Type: text/event-stream
Cache-Control: no-cache
data: {"message":"First chunk"}\n\n
data: {"message":"Second chunk"}\n\n
data: {"message":"Third chunk"}\n\n
각 이벤트는 다음과 같습니다:
data:로 시작합니다.- 페이로드(payload)를 포함합니다.
\n\n(두 개의 줄 바꿈)으로 끝납니다.
명명된 이벤트
event: recommendation
data: {"petId":"019b4132","score":0.95}
event: recommendation
data: {"petId":"019b4127","score":0.89}
event: complete
data: {"total":2}
이벤트 ID
id: 1
data: {"message":"First"}
id: 2
data: {"message":"Second"}
클라이언트는 연결이 끊어졌을 경우 마지막 ID부터 재개할 수 있습니다.
SSE 서버 구현
Node.js/Express 예시
app.get('/v1/pets/recommendations/stream', async (req, res) => {
// SSE 헤더 설정
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
// 추천이 생성되는 즉시 전송
const recommendations = await generateRecommendations(req.query.userId);
for (const rec of recommendations) {
res.write(`data: ${JSON.stringify(rec)}\n\n`);
await sleep(100); // 스트리밍 지연 시뮬레이션
}
// 완료 이벤트 전송
res.write(`event: complete\ndata: {"total":${recommendations.length}}\n\n`);
res.end();
});
Python/FastAPI 예시
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
import json
import asyncio
app = FastAPI()
@app.get("/v1/pets/recommendations/stream")
async def stream_recommendations(user_id: str):
async def generate():
recommendations = await get_recommendations(user_id)
for rec in recommendations:
yield f"data: {json.dumps(rec)}\n\n"
await asyncio.sleep(0.1)
yield f"event: complete\ndata: {json.dumps({'total': len(recommendations)})}\n\n"
return StreamingResponse(
generate(),
media_type="text/event-stream",
headers={
"Cache-Control": "no-cache",
"Connection": "keep-alive"
}
)
SSE 클라이언트 구현
JavaScript/브라우저
const eventSource = new EventSource(
'https://petstoreapi.com/v1/pets/recommendations/stream?userId=user-456'
);
eventSource.onmessage = (event) => {
const data = JSON.parse(event.data);
displayRecommendation(data); // 추천 표시
};
eventSource.addEventListener('complete', (event) => {
const data = JSON.parse(event.data);
console.log(`Received ${data.total} recommendations`); // ${data.total}개의 추천을 받았습니다
eventSource.close();
});
eventSource.onerror = (error) => {
console.error('SSE error:', error); // SSE 오류:
eventSource.close();
};
React 훅
import { useEffect, useState } from 'react';
function useSSE(url) {
const [data, setData] = useState([]);
const [complete, setComplete] = useState(false);
useEffect(() => {
const eventSource = new EventSource(url);
eventSource.onmessage = (event) => {
const item = JSON.parse(event.data);
setData(prev => [...prev, item]);
};
eventSource.addEventListener('complete', () => {
setComplete(true);
eventSource.close();
});
return () => eventSource.close();
}, [url]);
return { data, complete };
}
// 사용법
function Recommendations({ userId }) {
const { data, complete } = useSSE(
`https://petstoreapi.com/v1/pets/recommendations/stream?userId=${userId}`
);
return (
<div>
{data.map(rec => (
<PetCard key={rec.petId} pet={rec} />
))}
{!complete && <Spinner />}
</div>
);
}
Modern PetstoreAPI가 SSE를 사용하는 방법
AI 반려동물 추천
AI 생성 추천 스트리밍:
GET /v1/pets/recommendations/stream?userId=user-456
Accept: text/event-stream
event: recommendation
data: {"petId":"019b4132","name":"Fluffy","score":0.95,"reason":"Matches your preference for cats"} // 고양이에 대한 선호도와 일치합니다
event: recommendation
data: {"petId":"019b4127","name":"Buddy","score":0.89,"reason":"Similar to pets you liked"} // 좋아했던 반려동물과 유사합니다
event: complete
data: {"total":2,"processingTime":850}
주문 상태 업데이트
주문 처리 단계 스트리밍:
GET /v1/orders/019b4132/status/stream
Accept: text/event-stream
data: {"status":"payment_processing","timestamp":"2026-03-13T10:30:00Z"} // 결제 처리 중
data: {"status":"payment_confirmed","timestamp":"2026-03-13T10:30:02Z"} // 결제 확인됨
data: {"status":"preparing_shipment","timestamp":"2026-03-13T10:30:05Z"} // 배송 준비 중
event: complete
data: {"status":"shipped","trackingNumber":"1Z999AA10123456784"} // 배송됨
재고 변경
실시간 재고 업데이트 스트리밍:
GET /v1/inventory/stream
Accept: text/event-stream
event: stock-change
data: {"petId":"019b4132","oldStock":5,"newStock":4} // 재고 변경
event: price-change
data: {"petId":"019b4127","oldPrice":299.99,"newPrice":279.99} // 가격 변경
Modern PetstoreAPI SSE 문서를 참조하세요.
Apidog으로 SSE 테스트하기
Apidog은 SSE 테스트를 지원합니다:
- SSE 요청 생성
Accept: text/event-stream설정- 실시간으로 이벤트 연결 및 확인
- 이벤트 형식 검증
- 재연결 테스트
모범 사례
1. 적절한 헤더 설정
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
res.setHeader('X-Accel-Buffering', 'no'); // Nginx 버퍼링 비활성화
2. 하트비트 전송
연결 유지:
const heartbeat = setInterval(() => {
res.write(': heartbeat\n\n');
}, 15000);
res.on('close', () => clearInterval(heartbeat));
3. 오류를 우아하게 처리
eventSource.onerror = (error) => {
if (eventSource.readyState === EventSource.CLOSED) {
// 연결이 닫혔으며, 자동으로 재연결될 것입니다.
} else {
// 기타 오류
console.error('SSE error:', error); // SSE 오류:
}
};
4. 재개를 위한 이벤트 ID 사용
let lastEventId = 0;
app.get('/stream', (req, res) => {
const startId = parseInt(req.headers['last-event-id'] || '0');
for (let i = startId + 1; i <= 100; i++) {
res.write(`id: ${i}\ndata: {"message":"Event ${i}"}\n\n`);
}
});
5. 연결 닫기
// 클라이언트
eventSource.addEventListener('complete', () => {
eventSource.close();
});
// 서버
res.on('close', () => {
// 리소스 정리
});
결론
SSE는 API 응답 스트리밍에 완벽합니다. 단방향 통신에 WebSocket보다 간단하고, HTTP를 통해 작동하며, 재연결을 자동으로 처리합니다.
Modern PetstoreAPI는 AI 스트리밍, 주문 업데이트 및 실시간 피드에 SSE를 사용합니다. Apidog으로 SSE 엔드포인트를 테스트하세요.
자주 묻는 질문
SSE는 기업 방화벽을 통해 작동할 수 있나요?
예, SSE는 표준 HTTP/HTTPS를 사용하므로 대부분의 방화벽과 프록시를 통해 작동합니다.
SSE 연결은 얼마나 오래 열려 있을 수 있나요?
무기한으로 열려 있을 수 있지만, 프록시를 통해 연결을 유지하려면 15-30초마다 하트비트를 사용해야 합니다.
SSE를 통해 바이너리 데이터를 보낼 수 있나요?
아니요, SSE는 텍스트 전용입니다. 바이너리 데이터는 Base64로 인코딩하거나 대신 WebSocket을 사용하세요.
SSE는 양방향 통신을 지원하나요?
아니요, SSE는 서버-클라이언트 단방향 통신만 지원합니다. 클라이언트는 클라이언트-서버 통신을 위해 일반 HTTP 요청을 사용합니다.
브라우저는 몇 개의 SSE 연결을 가질 수 있나요?
브라우저는 도메인당 SSE 연결 수를 제한합니다(일반적으로 6개). 많은 연결을 위해서는 멀티플렉싱 또는 WebSocket을 사용하세요.
