iframe 을 사용한 Cross-Origin 파일 다운로드 하기

+ 파일 다운로드 UX 를 고려한 여러 고민들

개요

회사에서 화상 미팅 서비스에 대용량이 가능한 채팅 파일 공유 기능을 개발하고 있다. 파일 공유로 S3 presigned URL 을 받아오고 있다. 이 URL 을 다운로드 받기 위해서 a 태그를 사용할 수 없었다. 이유는 a 태그의 download 속성은 Same-Origin URL, blob:, data: 스킴에서만 동작한다. [참고]

target="_blank" 속성을 주는 방법도 있었지만 그렇게 된다면 화상미팅 도중 공유된 파일 확인 시 새탭으로 이동하게 되어 미팅 UX 가 나빠질 우려가 있었다.

해당 문제를 해결하기 위해 여러가지 레퍼런스 조사를 진행했고, 여러 테스트를 거쳐 iframe 을 사용하는 방법으로 이슈를 해결했다.

주의사항

먼저 설명하기에 앞서 주의해야 할 사항이 두가지 존재한다.

  1. 다운로드 받을 파일에 Content-Disposition: attachment HTTP 헤더가 있어야 한다. [참고]

  2. iOS 에서는 동작하지 않는다.

    • iOS 에서 동작하지 않는 이유는 sandbox 속성의 allow-downloads 를 지원하지 않아서라고 생각한다. [참고]

iframe src 를 활용한 파일 다운로드

const isIos = () => window.navigator.userAgent.match(/ipad|iphone/i) !== null;

const download = (url) => {
    if (isIos()) {
        window.open(url, '_blank');
        return;
    }

    const iframe = document.createElement('iframe');

    iframe.src = url;
    iframe.style.display = 'none';
    document.body.appendChild(iframe);
};
  • DOM 트리에 iframe 이 추가 되면서 파일을 불러오게 되고 Content-Disposition 헤더로 파일 다운로드가 시작된다.

  • 생성한 iframe 의 src 를 변경하는것 만으로 다른 파일도 다운로드 받을 수 있다.

iframe 내부 anchor 태그로 파일 다운로드

const isIos = () => window.navigator.userAgent.match(/ipad|iphone/i) !== null;

const download = (url, fileName = '') => {
    const iframe = document.createElement('iframe');

    iframe.src = 'about:blank';
    iframe.style.display = 'none';
    document.body.appendChild(iframe);

    const anchor = iframe.contentDocument.createElement('a');
    anchor.download = fileName ;
    anchor.href = url;
    if (isIos()) {
        anchor.target = '_blank';
    }
    iframe.contentDocument.body.appendChild(anchor);

    anchor.click();
};
  • 이 방법으로도 파일을 다운로드 받을 수 있다.

파일 다운로드 기능을 개발하기위한 여러 시도들

했던 시도들이 아쉬워서 글 끄트머리에 넣어보려고 한다.

  1. Next.js Middleware 의 rewrites 시도 + <a download />

  2. Ctrl + Click 액션 재현 시도

  3. window.focus 를 활용해 현재 탭 포커싱 유지 시도

이 중 Next.js 시도에 대해 얘기 해보려고 한다. Next.js 의 Middleware 를 사용하지 않은 이유는 두가지가 있었는데,

첫째는 현재 진행중인 프로젝트가 AWS CodeBuild 를 통해 ECS 로 Blue/Green 배포 방식이 적용된 상태이다. rewrites 를 통해 다운로드 받은 시점의 CPU 사용량을 체크해보니 최대 평균 사용량이 1% → 10% 로 크게 증가한 모습을 보였다.

둘째는 rewrites 를 통해 대용량 파일을 다운로드 받을 시 서버가 꺼지게 되면 네트워크 에러로 다운로드가 실패 한다. Blue/Green 배포 테스트를 해보니 짧은 시간 순단이 발생하는 상황이 발생했다.

마무리

iframe 을 통한 두가지 다운로드 방법은 아래 URL 을 통해 직접 테스트 해 볼 수 있다.