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

## 개요

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

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

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

## 주의사항

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

1. 다운로드 받을 파일에 `Content-Disposition: attachment` HTTP 헤더가 있어야 한다. \[[참고](https://developer.mozilla.org/ko/docs/Web/HTTP/Headers/Content-Disposition)\]
    
2. iOS 에서는 동작하지 않는다.
    
    * iOS 에서 동작하지 않는 이유는 sandbox 속성의 `allow-downloads` 를 지원하지 않아서라고 생각한다. \[[참고](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#allow-downloads)\]
        

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

```javascript
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 태그로 파일 다운로드

```javascript
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 을 통해 직접 테스트 해 볼 수 있다.

* code: [https://stackblitz.com/edit/stackblitz-starters-dvdzn9?file=src%2FApp.tsx](https://stackblitz.com/edit/stackblitz-starters-dvdzn9?file=src%2FApp.tsx)
    
* preview: [https://stackblitz-starters-dvdzn9.stackblitz.io](https://stackblitz-starters-dvdzn9.stackblitz.io)
