파일 다운로드 기능 구현하기 :: 마이구미
이 글은 자바스크립트를 통해 파일 다운로드 기능을 구현해본다.
파일 다운로드 기능은 클라이언트에서 제공해주거나 서버에서 제공해줄 수 있다.
2가지 방식에 대한 구현 및 주의사항, 웹앱 이슈 등을다뤄본다.
파일 다운로드 방식에 있어서, 2가지 방식은 무엇인가?
2가지의 기준은 클라이언트와 서버로 기능을 제공하는 주체가 된다.
간단하게 말하면, "서버 도움 없이 클라이언트 사이드에서 제공하는 것"과 "서버 사이드에서 다운로드를 위한 API" 를 제공해주는 것이다.
클라이언트 사이드에서 이를 제공할 수 있는 방식은 다음과 같다.
a 태그에서 download 속성이라는 것을 제공해준다.
<a href="https://**/images/mygumi.jpg" download>
서버에서 제공해주는 방식은 다음과 같다.
HTTP 응답 헤더인 Content-Disposition 를 활용하는 것이다.
이를 이용해서 서버에서 다운로드 API 를 제공한다.
// Reponse Header
Content-Disposition: attachment; filename="filename.jpg"
// front code
const blob = response.data;
const disposition = response.headers['content-disposition']
const fileName = decodeURI(disposition.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/)[1].replace(/['"]/g, ''))
const a = document.createElement('a');
a.href = window.URL.createObjectURL(blob);
a.download = fileName;
a.click();
"클라이언트 사이드에서 제공하는 방식" 과 같은 방식이면서 서버의 응답값을 사용하면 된다.
어떤 방식을 사용해야하는가?
상황과 목적에 따라 다를 것이다.
예를 들어 정적인 파일이 아니라 동적인 파일이라면 당연히 서버에서 API 형태로 제공해줘야한다.
반대로 양식 파일과 같이 변하지 않는 정적인 파일이라면 API 없이 클라이언트에서 제공할 수 있다.
사실 웬만하면 서버 API 형태가 존재하는 것이 가장 좋다.
이유는 브라우저, OS 에 따른 호환성 문제이다.
HTTP 헤더를 활용하는 방식으로 클라이언트 사이드 방식보다 호환성이 높다.
물론 호환을 위해 클라이언트에서의 다운로드를 위한 FileSaver 라이브러리가 존재한다.(README.md 와 코드가 길지 않으니 참고해보길 바란다.)
하지만 이것 또한 모든 경우를 커버할 수 있지 않고, 라이브러리에서도 가능하다면 서버에서 제공하길 추천하고 있다.
예를 들어, 웹뷰로 제공하는 IOS 웹앱에서도 다운로드 기능이 동작되려면 네이티브앱에서 구현해야한다.
앱을 대응해야한다면, 네이티브앱에서 API 형태를 호출해야하는 방향으로 가기 때문에 결국 API 는 존재해야한다.
요약
"단순한 정적 파일 다운로드 기능으로 서버 API 까지 요구할 필요 없이 클라이언트 사이드에서 제공하자"
위 요구를 받아들여도 될 것 같지만, 웹뷰 형태의 네이티브 앱을 제공하고 있다면 위의 요구를 받아들이면 안된다.
"단순한 정적 파일 다운로드 기능이고 앱이 PC 웹 브라우저만 지원하면 되니 클라이언트 사이드에서 제공해도 돼"
위 요구라면 받아들일 수 있다.
그 외 이슈
a download 속성
a 태그의 download 속성은 IE 하위버전에서 지원해주지 않기 때문에 분기 처리가 필요하다.
이를 위해서는 navigator.msSaveOrOpenBlob 메소드를 사용하면 된다.
비표준이고 중단된 문구가 보이더라도 IE 를 위한 것이기에 신경쓰지않아도 된다.
그 외에도 브라우저마다 다른 처리가 필요할 수 있기에, 언급된 FileSaver 와 같은 라이브러리를 사용하는 것을 추천한다.
Content-Disposition
API 의 응답으로 Content-Disposition 헤더가 개발자 도구에서는 확인이 가능하다.
하지만 실제로 접근하면 undefined 값이 출력된다.
이 문제는 CORS 이슈로 기본적으로 접근이 허용되지 않는 헤더이다.
서버에서 exposeHeaders 작업을 해줘야 클라이언트에서 접근해서 사용할 수 있다.
웹뷰로 제공되는 네이티브 앱
- AOS
안르도이드 웹뷰에서 제공해주는 setDownloadListener 를 활용해서 웹뷰의 다운로드 기능을 사용할 수 있다.
- IOS
네이티브 앱에서 다운로드 기능을 구현한 후, injectJavascript 와 같은 기능을 네이티브에서 제공해주는 메소드를 웹뷰 내에서 실행해줘야하는 것으로 추정.
잘못된 내용이 있거나 오해하고 있는 내용이 있으면 댓글로 남겨주세요!