-
새 탭 열림 없이 파일 다운로드: Blob으로 해결하기개발 여정/FrontEnd 2025. 5. 6. 22:04
예전에 실무에서 일을 했을 때, pdf나 jpg 파일 링크를 클릭하면 사용자가 다운받게 하는 기능을 만든 적이 있다. 이렇게 보면 매우 간단하지만, PM이 요구한 다음과 같은 조건이 나를 난감하게 했다.
- 새 탭 열기 없이
- 지정된 파일명으로 다운받아지게 할 것...
특히 새 탭 열기 없이 << 이 부분이 나에게 많은 물음표를 뜨게 했다. 대부분의 브라우저는 pdf나 jpg 링크를 클릭했을 때 새 탭을 열어서 보여주기 때문에.
그래서 열심히 서치를 하던 중 Blob의 존재를 알게 됐고, 위 문제를 손쉽게 해결할 수 있게 해주었다.
그럼 저 까다로운 조건을 가능하게 해준 고마운 Blob이란 건 뭘까?
Blob이란?
Blob은 Binary Large Object의 준말로, 이미지, 사운드, 비디오와 같은 멀티미디어 데이터를 이진(Binary) 형태로 임시 저장할 수 있는 객체다.
Blob을 비유하자면 택배 상자와 같다.
- 상자 안에 어떤 물건(데이터)가 들었는지는 중요하지 않음.
- 중요한 건 '이 상자 안에 어떤 데이터가 들어있다'라는 것.
- 이 상자를 이용해서 다운로드, 업로드, 파일 미리보기, url 생성 등을 할 수 있음.
즉 Blob은 데이터를 포장해서, 브라우저가 파일처럼 취급하게 만드는 기술이라고 이해할 수 있다.
자바스크립트로 '파일'을 만들어주는 도구
실제 파일이 아니더라도 blob을 거치면 파일 형태로 변환되어 사용할 수 있다. 예를 들어, 일반
'Hello, World!'
문자열도 Blob 생성자를 통해 text 파일로 거듭날 수 있다.const blob = new Blob(["Hello, World!"], {type: 'text/plain'})
파일을 다운로드할 수 있게 도와주는 도구
일단 파일 링크는 브라우저의 영향을 받는다.
다음과 같이 a 링크가 있다고 가정해보자.
<a href="https://myFile.pdf" />
브라우저는 이를 보고
- 새 탭에서 열지
- 다운로드를 할지
- 무시할지
를 판단하고, 이는 브라우저마다 기준도 다르다.
따라서 같은 링크라도 브라우저마다 반응이 다르다. 현재 탭에서 열릴 수도 있고, 새 탭에서 열릴 수도 있고, 새 탭에서 열리면서 파일이 다운로드될 수도 있고, 이 모든 게 작동하지 않을 수도 있다.
그러면 a 태그에
download
속성을 추가하면 되는 거 아냐? 라고 할 수 있지만, 쉽게 사용하기엔 또 다른 제약들이 있다.CORS 이슈
일단
download
속성은 같은 origin일 때만 작동한다.// 파일을 여는 사이트 도메인이 myWolrld.com일 때 <a href="https://myWolrd.com/file.pdf" download />✅ 잘 됨 <a href="https://otherWorld.com/file.pdf" download /> ❌ CORS 이슈 발생 가능
파일 링크가 두번째처럼 다른 도메인이라면, 보안 때문에 CORS(Cross-Origin Resource Sharing) 이슈가 발생하면서 다운로드가 동작하지 않을 수 있다.
서버 헤더 응답
서버 응답 헤더에도 영향을 받는다.
서버 응답 헤더에서 다음과 같이 설정되어 있다면,Content-Disposition: inline
다운로드는 작동되지 않고 브라우저는 그냥 파일을 열어버린다.
즉, 서버가 통제권을 가지기 때문에 프론트에서
download
속성을 강제할 수 없는 경우가 많다.Blob을 사용한다면?
Blob을 사용한다면 다음과 같은 장점을 통해 위 이슈들을 해결할 수 있다.
- 새 탭 열기 이슈: Blob URL은 브라우저를 위한 임시 url이기 때문에, 브라우저가 '외부 자원'으로 간주하지 않아 새 탭 열기 동작을 실행하지 않음.
- CORS 이슈: Blob URL은 브라우저 내부 리소스이기 때문에, CORS 요청을 거치지 않음.
- 다운로드 이슈: 마찬가지로 Blob URL이 브라우저 내부 리소스이기 때문에 서버 응답에 통제를 받지 않음. 따라서 다운로드를 강제할 수 있음.
그리고 Blob URL은 브라우저 내부에서만 유효한 임시 주소이기 때문에 보안적 측면에서도 강점이 있다.
- 외부에서 접근 불가능
- 세션 종료되면 자동 폐기됨
- 서버에 저장하지 않아도 되므로 개인정보 보호에 유리
실제 코드 예시: Blob으로 새탭열기 없이 파일 저장하기
위에서처럼 Blob을 통하면 브라우저 설정에도, 서버에도 영향을 받지 않기 때문에 내가 원하는 방식인
- 새 탭 열기 없이
- 바로 다운로드 (지정된 파일명과 함께)
를 실현할 수 있었다.
const handleDownloadOnWeb = async (url: string) => { const response = await fetch(url); // 파일 데이터를 비동기 fetch const blob = await response.blob(); // 응답을 Blob으로 변환 const binary = new Blob([blob], { type: blob.type }); // Blob 재포장 const windowUrl = window.URL.createObjectURL(binary); // 가짜 주소(URL) 생성 const link = document.createElement('a'); // <a> 태그 동적으로 생성 link.href = windowUrl; link.setAttribute('download', 'report.pdf'); // 저장할 파일명 지정 document.body.appendChild(link); // DOM에 추가 link.click(); // 클릭 이벤트 발생시켜 다운로드 실행 link.remove(); // DOM에서 제거 window.URL.revokeObjectURL(windowUrl); // 메모리에서 URL 해제 };
비교: 일반 다운로드 방식과의 차이
기능 Blob 방식 일반 방식 새 탭 없이 저장 ✅ 가능 ❌ 서버 헤더/브라우저 영향 받음 파일명 지정 ✅ 가능 ( download
)❌ 외부 링크는 불가능 클라이언트에서 만든 데이터 저장 ✅ 가능 ❌ 불가 다른 origin 파일 다운로드 ✅ 대부분 가능 ❌ 브라우저 제약 많음 Blob URL 사용 시 주의해야 할 점
URL.createObjectURL
로 만든 url은 브라우저 메모리를 사용하기 때문에,- 사용 후
URL.revokeObjectURL()
로 꼭 해제해야 한다.
- 사용 후
- 일부 오래된 브라우저(ex. IE11)는 Blob 지원이 잘 안 될 수도 있다.
'개발 여정 > FrontEnd' 카테고리의 다른 글
Next.js 13 (App Router) 예상 면접 질문 (2) (0) 2025.05.21 Next.js 13 (App Router) 예상 면접 질문 (1) (0) 2025.05.19 Next.js의 dynamic import: 필요할 때만 불러와서 로딩 최적화하기 (0) 2025.04.29 TypeScript의 Record란? (0) 2025.04.27 TypeScript의 제네릭(Generic)이란? (0) 2025.04.21