javascript 에서 사이즈 큰 파일(large file) 다운로드 시 문제

sig03
4 min readJun 24, 2021

javascript 에서 파일 다운로드를 구현했다. axios 에서 다운로드 api를 호출해서 a 태그를 생성해 다운로드 받는 방식. 찾아보면 아래와 같은 예제가 일반적이다. onDownloadProgress 는 다운로드 시 용량을 체크해 ui 표시해주기 위한 이벤트이다.

export const getFileDownload = (key:keyProps, setDownProgress:any) => {
const token = getToken();
return axios({
method: 'POST',
url: ServerInfo + Download,
responseType: 'blob',
onDownloadProgress:(evt) => {
let progress = Math.round((evt.loaded / evt.total) * 100);
setDownProgress(progress)
},
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer '+ token,
'X-Requested-With': 'XMLHttpRequest'
},
params : {
key: key
}
});
};
const fileDownload = getFileDownload(key, type, setDownProgress);
fileDownload.then (response => {
const type = response.headers['content-type'];
const blob = new Blob([response.data], { type: type + ';charset:UTF-8' });
const link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = selectedResource.resourceName;
link.click();
link.remove();
});

작은 파일을 받을때 위와 같은 소스에 문제는 없다. 그런데 문제는 사이즈가 큰 파일을 받을때이다. 또 보통 두 개 이상의 파일을 받을때 압축을 해서 받는데 그때도 문제가 있다.

어떤 문제가 있나? xhr로 다운 받으면 일단 브라우저에 한번 받고 그 다음 로컬에 받는다. 브라우저로 받을때 파일 사이즈가 크면 메모리를 잔뜩 잡아 먹는다. 사파리의 경우 메모리 문제로 중단되 버린다. 또 브라우저에 한참 받고 다시 로컬로 받는 두 번의 과정을 거치기 때문에 다운받는 속도도 두 배로 늘어난다. axios 의 onDownloadProgress 이벤트에 다운로드 프로그레스를 표시했는데 그러면 프로그레스가 100%차도 다시 로컬로 다운받는 과정을 반복하는 이상해 보이는 문제가 발생한다. (다운을 두번하네? ) 이래저래 브라우저에 받으면 문제가 있다.

간단한 방법은 form submit을 하면 된다. 그런데 토큰과 같이 헤더에 인증값을 보내줘야 하는데 form submit을 하면 또 그걸 못한다. 헤더값 세팅을 못함. 아무리 찾아봐도 방법이 없다. 자바스크립트에서 큰 파일 다운받는 작업을 하는 사람들이 많지 않아서 그런지 구글을 아무리 뒤져도 좋은 방법이 없었다.

결국 form submit을 하는데 대신 토큰값을 hidden 으로 전송하는 방법으로 해결했다. 서버쪽에서는 파라메터 토큰값으로 인증을 처리하고. 아래는 react에서 다운로드 form submit 하는 예제이다.

const formRef = useRef(null);...formRef.current.submit();...<form ref={formRef} name="formRef" method="post" action={downloadUrl}>
<input type="hidden" name='token' value={token} />
<input type="hidden" name='key' value={key} />
<input type="hidden" name='type' value={type} />
</form>

--

--