Node.js · 2026-01-05

Node.js로 비디오 스트리밍: 범위 요청과 반응형 처리

Node.js 환경에서 Range 요청 기반 비디오 스트리밍과 반응형(Adaptive) 스트리밍의 개념, 서버 구현 예제, 클라이언트 연동과 성능 고려사항을 정리한 설명

작성일 : 2026-01-05 ㆍ 작성자 : 관리자
post
목차

소개

웹에서 동영상을 부드럽게 재생하려면 서버가 범위 요청(Range request)을 정확히 처리해야 한다. 브라우저는 비디오 재생 시 구간 요청을 통해 원하는 바이트만 내려받는다. 이 글은 Node.js 비디오 스트리밍 구현 원리와 샘플 코드를 중심으로 범위 요청 처리 방법과 반응형 스트리밍 접근을 알기 쉽게 정리한다.

범위 요청의 기본 원리

HTTP Range 헤더는 클라이언트가 파일의 일부만 요청하도록 만든다. 비디오 태그나 미디어 플레이어는 재개, 탐색, 버퍼링 최적화를 위해 이 기능을 사용한다. 서버는 요청을 파싱해서 해당 바이트 구간을 읽어 206 Partial Content로 응답한다.

주요 헤더

  • Range: bytes=start-end — 클라이언트가 요청하는 바이트 범위
  • Accept-Ranges: bytes — 서버가 범위 요청을 지원함을 알림
  • Content-Range: bytes start-end/total — 응답에 포함된 구간과 전체 크기
  • Content-Length — 전송할 바이트 길이

Node.js 기본 구현 (http 모듈)

아래 예제는 파일에서 바이트 구간을 잘라 스트리밍하는 간단한 서버 코드다. 파일 크기를 얻고 Range 헤더를 파싱한 뒤 createReadStream으로 부분 스트림을 전송한다.

const http = require('http');
const fs = require('fs');
const path = require('path');

const filePath = path.join(__dirname, 'sample.mp4');

http.createServer((req, res) => {
  const stat = fs.statSync(filePath);
  const fileSize = stat.size;
  const range = req.headers.range;

  if (!range) {
    res.writeHead(200, {
      'Content-Length': fileSize,
      'Content-Type': 'video/mp4'
    });
    fs.createReadStream(filePath).pipe(res);
    return;
  }

  const parts = range.replace(/bytes=/, '').split('-');
  const start = parseInt(parts[0], 10);
  const end = parts[1] ? parseInt(parts[1], 10) : fileSize - 1;
  const chunkSize = (end - start) + 1;

  res.writeHead(206, {
    'Content-Range': `bytes ${start}-${end}/${fileSize}`,
    'Accept-Ranges': 'bytes',
    'Content-Length': chunkSize,
    'Content-Type': 'video/mp4'
  });

  fs.createReadStream(filePath, { start, end }).pipe(res);
}).listen(8000);

설명

  • Range 헤더가 없으면 전체 파일을 200으로 보낸다.
  • Range가 있으면 start, end를 계산해 206을 반환한다.
  • createReadStream의 start/end 옵션으로 효율적으로 부분 전송한다.

Express로 처리하기

Express 환경에서는 res.set과 res.status를 이용해 같은 동작을 구현한다. 파일이 큰 경우 스트림을 사용하면 메모리 부담을 줄일 수 있다.

const express = require('express');
const fs = require('fs');
const path = require('path');
const app = express();
const filePath = path.join(__dirname, 'sample.mp4');

app.get('/video', (req, res) => {
  const stat = fs.statSync(filePath);
  const fileSize = stat.size;
  const range = req.headers.range;

  if (!range) {
    res.set({ 'Content-Length': fileSize, 'Content-Type': 'video/mp4' });
    fs.createReadStream(filePath).pipe(res);
    return;
  }

  const parts = range.replace(/bytes=/, '').split('-');
  const start = parseInt(parts[0], 10);
  const end = parts[1] ? parseInt(parts[1], 10) : fileSize - 1;
  const chunkSize = (end - start) + 1;

  res.status(206);
  res.set({
    'Content-Range': `bytes ${start}-${end}/${fileSize}`,
    'Accept-Ranges': 'bytes',
    'Content-Length': chunkSize,
    'Content-Type': 'video/mp4'
  });

  fs.createReadStream(filePath, { start, end }).pipe(res);
});

app.listen(8000);

클라이언트 연동

브라우저의 <video> 태그는 기본적으로 범위 요청을 사용한다. 따라서 서버만 제대로 설정하면 별도 스크립트 없이 재생, 탐색, 재개가 동작한다. HLS 같은 반응형 스트리밍을 쓸 때는 hls.js 같은 라이브러리를 사용할 수 있다.

<video controls width="640" src="/video"></video>

반응형 스트리밍(Adaptive) 접근

범위 요청은 부분 전송에 적합하지만 네트워크 상태에 따라 화질을 바꾸려면 HLS나 DASH 같은 어댑티브 스트리밍을 도입한다. 일반적인 흐름은 다음과 같다.

  • 원본 파일을 다양한 비트레이트로 트랜스코딩
  • 각 화질을 짧은 세그먼트(예: 6초)로 분할
  • .m3u8(또는 MPD) 플레이리스트를 생성해 세그먼트 목록 제공
  • 클라이언트는 네트워크 상태에 맞게 세그먼트 URL을 선택해 가져옴

서버는 세그먼트를 정적 파일처럼 서빙하면 된다. HLS 생성은 ffmpeg로 자동화할 수 있다.

성능과 운영상 고려사항

  • CORS 설정: 외부 도메인에서 재생하려면 Access-Control-Allow-Origin 설정 필요
  • 캐시와 CDN: 대용량 트래픽은 CDN으로 분산해 응답 속도와 비용 절감
  • 동시 연결: createReadStream은 메모리를 적게 쓰지만 파일 디스크립터 수를 고려
  • 다중 범위 요청: 브라우저가 여러 범위를 요청할 가능성은 낮지만, 지원이 필요하면 멀티파트 응답 처리 고려
  • 보안: 인증이 필요한 콘텐츠는 토큰 기반 URL 또는 서명된 URL 사용

마무리 요약

Node.js로 비디오 스트리밍 구현은 Range 요청을 정확히 파싱해 206 응답을 주는 것이 핵심이다. 간단한 http나 Express 서버로도 충분히 동작하며, 어댑티브 스트리밍이 필요하면 HLS/DASH로 확장한다. 테스트는 다양한 브라우저와 네트워크 환경에서 재생, 탐색, 재개를 확인한다.

참고 키워드

  • Node.js 비디오 스트리밍 구현
  • range 요청 비디오 스트리밍 Node
  • Node 동영상 스트리밍 예제
Node.js 비디오 스트리밍 구현 range 요청 비디오 스트리밍 Node Node 동영상 스트리밍 예제 HTTP Range Express 비디오 스트리밍 HLS Adaptive 스트리밍 비디오 스트리밍 성능