Streamable HTTP란?

쭌로그·약 13시간 전

Streamable HTTP란 무엇인가?

Streamable HTTP는 기존 HTTP 위에서 동작하면서도, 요청·응답을 스트리밍 형태로 주고받을 수 있게 확장한 전송 방식입니다. MCP(Modal Context Protocol) 같은 AI 프로토콜에서 기존 HTTP+SSE(Server-Sent Events)의 한계를 보완하기 위해 도입되었습니다.


1. HTTP와 SSE의 한계

기존의 HTTP와 SSE에는 아래와 같은 문제점이 있었습니다.

  • HTTP + SSE의 한계

    • 긴 연결을 유지해야 해서 서버 리소스 부담이 큼.
    • API 호출용 엔드포인트와 SSE용 엔드포인트를 따로 관리해야 함.
    • 일부 프록시, 게이트웨이, CDN 환경에서 SSE에 제약이 존재.
    • 구조적으로 서버→클라이언트 단방향 스트림에 치우쳐 있어 양방향 상호작용 설계가 번거로움.
  • Streamable HTTP가 해결할 수 있는 것

    • 표준 HTTP 메서드(GET, POST 등)를 그대로 쓰면서,
    • 응답을 한 번에 보내지 않고 여러 조각(chunks)으로 나누어 “흘려보내는” 스트리밍 모델을 제공.
    • 단일 엔드포인트에서 요청·응답·스트리밍을 모두 처리.
    • 상태 비저장(stateless) 서버와도 잘 맞는 구조.

HTTP는 유지하되, WebSocket과 같은 실시간성 경험"을 만들기 위한 새로운 방식이 Streamable HTTP입니다


2. Streamable HTTP의 개념

표준 HTTP 위에서 동작하는 스트리밍 응답 패턴이다.

  • 클라이언트는 HTTP 요청(주로 POST)을 보낸다.
  • 서버는 HTTP 응답을 바로 닫지 않고 열어 둔 채,
    • JSON 조각, 텍스트 블록, 이벤트 형태의 메시지를 여러 번에 걸쳐 전송한다.
  • 클라이언트는 이 스트림을 읽어가며 UI를 점진적으로 업데이트한다.

예: AI에게 긴 보고서 요약을 요청했을 때, 기존 HTTP는 요약이 끝난 뒤 전체 텍스트를 한 번에 내려준다. Streamable HTTP에서는 “문단 단위” 혹은 “토큰 단위”로 결과가 생성되는 즉시 클라이언트로 흘려보낼 수 있다.


3. Streamable HTTP의 특징

3.1 스트리밍 응답

  • 서버는 응답을 한 번에 보내지 않고 여러 chunk로 분할해 전송한다.
  • 클라이언트는 스트림이 열려 있는 동안 데이터가 올 때마다 소비할 수 있다.
  • 사용자 경험 측면에서 “실시간에 가깝게” 결과를 볼 수 있다.

3.2 단일 엔드포인트 + 표준 HTTP 메서드

  • 보통 /message 같은 하나의 URL로 다음을 모두 처리한다.
    • POST: 새로운 요청(예: 채팅 메시지, 작업 시작 등)
    • GET: 스트림 조회, 재개, 상태 확인 등
  • 별도의 SSE 전용 엔드포인트를 두지 않아도 된다.

3.3 상태 비저장(stateless) 서버 친화적

  • 서버는 매 요청을 독립적으로 처리하고, 필요 시 연결을 끊을 수 있다.
  • 세션을 유지하려면 Session-Id 헤더나 토큰 등을 클라이언트가 함께 보내고,
    서버는 이를 기반으로 필요한 범위 내에서만 상태를 관리한다.

3.4 재개(resume) 가능 설계

  • 메시지 ID, 오프셋(offset) 등의 개념을 두면 스트림을 중간부터 다시 받을 수 있다.
  • 네트워크가 끊어졌을 때:
    • 클라이언트는 “마지막으로 받은 메시지 ID”를 기억해 두었다가,
    • 다시 요청하면서 마지막으로 가져온 ID 이후로 재개를 요청할 수 있다.

3.5 양방향 상호작용

  • 클라이언트 → 서버: 표준 HTTP 요청(POST, 경우에 따라 PUT/PATCH 등)
  • 서버 → 클라이언트: 스트리밍 응답(텍스트/JSON 이벤트 등)
  • 이를 조합하면 WebSocket 없이도 꽤 풍부한 양방향 상호작용 패턴을 만들 수 있다.

4. HTTP + SSE와의 비교

항목HTTP + SSEStreamable HTTP
통신 방향SSE는 서버→클라이언트 단방향 스트림, 요청은 별도 HTTPGET/POST 기반으로 양방향 상호작용 구성 가능
엔드포인트 구조REST API 엔드포인트 + SSE 엔드포인트를 별도로 운영/message 같은 단일 엔드포인트에서 요청·스트림 처리
연결 방식긴-lived 연결 유지, 서버 리소스 점유 큼필요 시에만 스트리밍, 짧은 HTTP 연결 조합도 가능
서버 상태상태 유지 구조에 의존하는 경우가 많음상태 비저장 서버 아키텍처에 잘 맞음
인프라 호환성일부 프록시/게이트웨이에서 SSE 제한표준 HTTP라 CDN·LB·API Gateway와 자연스럽게 호환
재시도/재개끊어지면 전체 스트림을 처음부터 재시작메시지 ID/offset 기반 재개 설계 용이

5. 동작 흐름 예시 (MCP 스타일)

MCP(Modal Context Protocol)에서 Streamable HTTP를 사용하는 시나리오를 예로 들면 다음과 같습니다.

5.1 요청 전송

  • 클라이언트는 MCP 서버의 /message 엔드포인트로 POST 요청을 보낸다.
  • 요청 바디에는 JSON-RPC 2.0 형식의 메시지(예: 메서드, 파라미터 등)를 담는다.
  • 인증이 필요하면 헤더에 토큰(JWT 등)을 함께 실어 보낸다.
POST /message HTTP/1.1
Host: api.example.com
Authorization: Bearer <token>
Content-Type: application/json

{
  "jsonrpc": "2.0",
  "id": "123",
  "method": "chat.send",
  "params": {
    "message": "요약 좀 해줘",
    "stream": true
  }
}

위 방식대로 호출하면 아래 방식처럼 api를 요청할 수 있습니다.

const response = await fetch("/message", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    // Authorization 등 필요한 헤더...
  },
  body: JSON.stringify({
    jsonrpc: "2.0",
    id: "123",
    method: "chat.send",
    params: { message: "요약 좀 해줘", stream: true }
  })
});

const reader = response.body?.getReader();
const decoder = new TextDecoder();

while (true) {
  const { done, value } = await reader.read();
  if (done) break;

  const chunk = decoder.decode(value, { stream: true });
  // chunk에는 여러 JSON 라인이 섞여 있을 수 있으므로,
  // 줄바꿈 기준 split 후 개별 JSON 파싱 등의 처리가 필요.
  console.log(chunk);
}

6. 정리

오늘은 Streamable에 대해 알아보았습니다. 아직 현업에서 SSE를 사용하지만 고도화가 진행될 때 Streamable HTTP를 도입하자고 제안할 계획이기에 매우 유익했던 학습이었습니다. 오늘도 긴 글 읽어주셔서 감사합니다!

Streamable HTTP 구현하기
Streamable HTTP가 현업의 표준이 된 이유

profile
매일 발전하는 프론트엔드 개발자

0개의 댓글