웹페이지에서 파일 다운로드 링크 제공 시 파일명 설정방법

Lemonade Engineering
Lemonade engineering
5 min readMar 19, 2021

by Jingi

서비스를 만들다보면 파일 다운로드 링크를 만들어야 할 때가 있다. 이런 경우 클라우드에 파일을 업로드하고, 해당 파일의 링크를 DB에 저장해 다운로드 링크로 제공하게 된다. 이 부분을 구현하며 다운로드 파일명이 생각보다 마음대로 설정되지 않았던 문제와 이를 해결하는 경험에 대해 써봤다.

왜 다운로드할 때 파일명이 이상하지?!

보통 인터넷에서 파일을 다운로드 받을 때는 링크를 클릭한다. 이 때 설정되는 파일명이 링크의 텍스트나 특정 속성의 값으로 자동 설정되는 것인 줄 알았는데 아니었다!!!(충격)

파일 다운로드를 제공해야하는 입장에서 어떻게 파일명을 설정해야할까? 우리 팀에서 사용하는 Google Cloud Storage를 기준으로 생각해봤다.

<a> 태그의 download 속성

먼저 구글링해보니 <a>태그의 download 속성이 파일명을 설정할 수 있도록 해준다고 나왔다.

download 속성은 연결된 URL로의 이동이 아닌 저장을 물어보게 만들어주는 속성으로, 값을 지정하면 해당 값을 파일명으로 지정해 다운로드를 제안하게된다.

<a 
href="https://storage.com/some_file.txt"
download="download.txt"
>
Download
</a>

왜 아직도 다운로드 파일명이 이상하지?!

download 속성에 값을 설정하는 방법은 Same Origin URL과 blob:, data: 스킴에서만 작동하기 때문! 이라고 MDN에 친절히 나와있었다.

친절한 MDN씨

첨부파일 업로드 기능에서 Google Cloud Storage에 파일을 업로드하고 업로드된 파일의 URL을 DB에 저장하고 있다. 이 URL이 첨부파일 다운로드 링크로 제공되고, 결국 Cross Origin으로 접근하게 되므로 download 속성이 효과가 없다.

위 설명에 따르면 Content-Disposition 헤더가 filename을 설정할 수 있는 다른 수단으로 보였고, Content-Disposition에 대한 설명을 읽어봤지만 어떻게 다운로드 파일명이 설정되는지 잘 모르겠어서 HTML 표준 문서를 찾아봤다.

외국어 교육 서비스를 만들지만 영어는 여전히 어렵…

리소스 다운로드와 관련된 HTML 표준에 따르면, Cross Origin 상황에서 브라우저는 사용자가 유해한 활동에 대한 경고를 받지않을 수 있도록 download 속성을 HTTP 응답 헤더의 (타입이 attachment인) Content-Disposition 필드와 연관지어야 한다.

테스트에 사용한 크롬 브라우저는 상황에 맞게 Google Cloud Storage에서 보내주는 HTTP 응답 헤더를 확인하는데, Content-Disposition 필드에 filename 정보가 없어서 URL 경로의 마지막 조각을 파일명으로 저장한 것이었다.

Content-Disposition: attachment

파일명을 따로 설정하고 싶다면 Content-Disposition 필드에 ';'(세미콜론)으로 구분하고 filename을 추가하며, 추가한 필드 값은 다음과 같다.

Content-Disposition: attachment; filename="filename.ext"

Google Cloud Storage에서 Content-Dispositionfilename 설정 방법

무엇이 문제인지 원인을 찾았고, 이제 수정할 차례! 우리가 사용하고 있는 Google Client Storage의 Node.js 클라이언트 라이브러리 문서에서 upload() 메소드를 호출할 때 넘겨주는metadata를 통해 contentDisposition를 설정해 전달할 수 있다는 것을 알 수 있었다.

await bucket.upload(file.path, {
destination: 'path/in/storage',
metadata: { contentDisposition: `attachment; filename="${file.name}"` },
});

이렇게 설정해서 업로드하자 다운로드 링크를 클릭했을 때 돌아오는 HTTP 응답 헤더에도 filename 필드가 설정됐다.

Content-Disposition: attachment; filename="filename.ext"

한 번 설정해보니 Google Cloud Storage외 다른 클라우드 스토리지들도 비슷한 설정 기능을 제공해줄 것이라고 예상된다.

마무리

다운로드 링크에 사용되는 <a> 태그, <a> 태그를 해석해 동작하는 브라우저, 브라우저가 받는 HTTP 응답 헤더, 이를 보내주는 Google Cloud Storage 까지 원인을 찾아 거슬러 올라가는 이 흐름에 백엔드 지식과 프론트엔드 지식이 모두 도움이 됐다. 간단하게 생각했던 다운로드 파일명 설정으로 HTML 표준 문서까지 살펴보게될 줄은 몰랐지만, 정확한 동작 원리와 지식을 학습할 수 있는 매우 유익한 경험이었다.

참고자료

https://developer.mozilla.org/ko/docs/Web/HTML/Element/a#특성

https://developer.mozilla.org/ko/docs/Web/HTTP/Headers/Content-Disposition

https://html.spec.whatwg.org/dev/links.html#downloading-resources

https://googleapis.dev/nodejs/storage/latest/Bucket.html#upload

--

--

Lemonade Engineering
Lemonade engineering

레모네이드 개발팀 기술 블로그입니다. This is an engineering blog from Lemonade Engineering.