Blob URL 다운로드 실패 문제 해결: revokeObjectURL의 중요성

기성·2026년 3월 12일

TIL

목록 보기
93/95

Blob URL 다운로드 실패 문제 해결: revokeObjectURL의 중요성

문제 상황

회사 프로젝트에서 백엔드로부터 PDF 파일을 Blob 형태로 받아 미리보기를 띄우고, 다운로드 기능을 제공하는 기능을 구현했습니다.

처음에는 잘 동작하는 것처럼 보였는데, 다운로드 버튼을 누를 때마다 이런 오류가 떴습니다.

"인터넷 연결이 안됨"

분명히 인터넷은 잘 연결되어 있고, 다른 API 요청도 정상적으로 작동하고 있는데 다운로드만 반복적으로 실패하는 상황이었습니다.


원인 분석: Object URL의 생명주기

문제를 이해하려면 먼저 createObjectURL이 어떻게 동작하는지 알아야 합니다.

window.URL.createObjectURL(blob)을 호출하면 브라우저는 해당 Blob 데이터를 메모리에 올리고, 아래와 같은 임시 URL을 생성합니다.

blob:https://your-site.com/550e8400-e29b-41d4-a716-446655440000

이 URL은 현재 브라우저 세션이 살아있는 동안 유효합니다. 하지만 명시적으로 해제하지 않으면 그 Blob 데이터는 메모리에 계속 남아있게 됩니다.

문제는 여기서 발생했습니다. 동일한 Blob에 대해 createObjectURL을 여러 번 호출하면서 이전 URL들이 해제되지 않고 쌓이다 보니, 브라우저가 해당 URL을 더 이상 유효하지 않은 리소스로 판단하고 "인터넷 연결이 안됨"이라는 오류를 뱉어낸 것입니다.


해결 방법: revokeObjectURL

핵심은 Object URL을 다 쓰고 난 뒤 반드시 해제해 주는 것입니다.

onSuccess: (blob) => {
  const url = window.URL.createObjectURL(blob);
  const previewWindow = window.open(url, "_blank");

  if (previewWindow) {
    // 새 창이 닫힐 때 blob URL 해제
    const timer = setInterval(() => {
      if (previewWindow.closed) {
        clearInterval(timer);
        window.URL.revokeObjectURL(url);
      }
    }, 500);
  } else {
    // 팝업 차단 시 직접 다운로드
    const link = document.createElement("a");
    link.href = url;
    link.download = "privacy_consent_preview.pdf";
    document.body.appendChild(link);
    link.click();
    link.remove();
    setTimeout(() => {
      window.URL.revokeObjectURL(url);
    }, 5000);
  }
},

코드를 단계별로 살펴보겠습니다.

1. Blob → Object URL 생성

const url = window.URL.createObjectURL(blob);
const previewWindow = window.open(url, "_blank");

백엔드에서 받은 Blob 데이터를 임시 URL로 변환하고, 새 탭에서 PDF 미리보기를 엽니다.

2. 새 창이 닫힐 때 URL 해제 (정상 케이스)

const timer = setInterval(() => {
  if (previewWindow.closed) {
    clearInterval(timer);
    window.URL.revokeObjectURL(url);
  }
}, 500);

setInterval로 500ms마다 새 창이 닫혔는지 체크합니다. 사용자가 미리보기 창을 닫으면 그때 revokeObjectURL을 호출해서 메모리를 해제합니다.

미리보기 창이 열려있는 동안은 URL이 살아있어야 PDF가 정상적으로 렌더링되기 때문에, 창이 닫히는 시점을 감지해서 해제하는 방식을 택했습니다.

3. 팝업 차단 시 fallback 처리

const link = document.createElement("a");
link.href = url;
link.download = "privacy_consent_preview.pdf";
document.body.appendChild(link);
link.click();
link.remove();
setTimeout(() => {
  window.URL.revokeObjectURL(url);
}, 5000);

브라우저 팝업 차단으로 새 창이 열리지 않은 경우, <a> 태그를 동적으로 생성해서 직접 다운로드를 트리거합니다. 이 경우에는 클릭 이후 5초 뒤에 URL을 해제합니다. (다운로드가 시작될 충분한 시간을 주기 위해)


정리

설명
createObjectURLBlob을 브라우저 메모리에 올리고 임시 URL 생성
revokeObjectURL생성한 임시 URL을 메모리에서 해제

Object URL은 쓰고 나면 반드시 해제해야 합니다. 그렇지 않으면 메모리 누수가 발생하고, 브라우저가 해당 URL을 유효하지 않은 리소스로 판단해 "인터넷 연결이 안됨" 같은 이상한 오류를 뱉을 수 있습니다.

Blob URL을 다루는 작업에서는 생성과 해제를 항상 쌍으로 처리하는 습관을 들이는 것이 중요합니다.

profile
프론트가 하고싶어요

0개의 댓글