Content-Disposition
사용법
일반적인 HTTP 응답에서 Content-Disposition 헤더는 브라우저가 콘텐츠를 사용자에게 어떻게 보여 줄지 제어합니다. 값을 inline으로 설정하면 브라우저가 콘텐츠를 직접 렌더링합니다. 값을 attachment로 설정하면 대신 다운로드 대화 상자가 뜹니다.
이 헤더는 multipart/form-data 응답과 폼 제출에서도 역할을 합니다. multipart 본문의 각 파트는 자체 Content-Disposition 필드를 포함하여 폼 필드 이름과, 업로드된 파일의 경우 선택적인 파일명을 식별합니다. 파트 경계는 Content-Type 헤더에 정의됩니다.
inline
inline 디렉티브는 콘텐츠를 페이지 안에 직접 표시하라고 브라우저에 지시합니다. 이는 Content-Disposition이 없을 때 대부분의 응답에서 적용되는 기본 동작입니다.
attachment
attachment 디렉티브는 다운로드 프롬프트를 띄웁니다. 브라우저는 콘텐츠를 뷰포트에 렌더링하는 대신 “다른 이름으로 저장” 대화 상자를 보여 줍니다.
filename
filename 매개변수는 내려받는 파일의 기본 파일명을 제안합니다. 값은 큰따옴표로 감싸며 ASCII 인코딩 규칙을 따릅니다.
Content-Disposition: attachment; filename="report.pdf"
filename*
filename* 매개변수는 ASCII를 넘어서는 문자 인코딩 지원을 더해 filename을 확장합니다. filename과 filename이 모두 있으면 filename이 우선합니다. 이는 ASCII가 아닌 문자가 들어간 파일명에 유용합니다.
Content-Disposition: attachment; filename="document.pdf"; filename*=UTF-8''d%C3%B6cument.pdf
form-data
form-data 디렉티브는 multipart 본문 파트에 나타나며 해당 콘텐츠가 폼 제출에 속함을 식별합니다.
name
name 매개변수는 multipart 본문 파트에서 필수이며, 해당 파트가 대응하는 폼 필드를 식별합니다.
예시
CSV 파일 다운로드로 응답하는 서버가 attachment를 설정하고 제안 파일명을 제공합니다. 브라우저는 “export.csv”가 미리 입력된 저장 대화 상자를 엽니다.
Content-Disposition: attachment; filename="export.csv"
PDF를 브라우저에 직접 표시하는 서버는 inline을 사용합니다. 브라우저는 파일을 내려받는 대신 내장 뷰어로 PDF를 렌더링합니다.
Content-Disposition: inline
multipart 폼 제출에서 각 파트는 자체 Content-Disposition 필드를 담습니다. name 매개변수는 파트를 해당 폼 필드에 대응시키고, filename은 업로드된 파일의 원래 이름을 나타냅니다.
Content-Disposition: form-data; name="avatar"; filename="photo.jpg"
문제 해결
Content-Disposition과 관련된 다운로드 및 표시 문제는 보통 잘못된 디렉티브 값이나 파일명 인코딩 실수에서 비롯됩니다.
파일이 엉뚱한 이름으로 내려받아집니다. 브라우저는 filename 매개변수를 기본 저장 이름으로 사용합니다. filename 값이 없거나 형식이 잘못되면 브라우저는 URL 경로나 일반적인 이름으로 되돌아갑니다. 값이 큰따옴표로 감싸여 있는지 확인하십시오. filename=“report.pdf” 처럼 씁니다. curl -I https://example.re/file 로 헤더를 확인하고 응답의 filename 매개변수를 점검하십시오.
파일명의 비ASCII 문자가 깨지거나 이상하게 표시됩니다. filename 매개변수는 ASCII 문자만 지원합니다. 악센트 문자, CJK 문자, 그 밖의 비ASCII 텍스트가 들어간 이름에는 인코딩 구문을 쓰는 filename* 매개변수를 추가하십시오. filename*=UTF-8”d%C3%B6cument.pdf 처럼 씁니다. 브라우저 간 최대 호환성을 위해 filename(ASCII 대체본)과 filename*(인코딩된 버전)을 모두 포함하십시오.
브라우저가 attachment를 무시하고 콘텐츠를 인라인으로 표시합니다. 일부 브라우저는 PDF나 이미지처럼 자체적으로 렌더링하는 콘텐츠 타입에 대해 attachment를 무시합니다. Content-Type 헤더가 이 동작에 영향을 줍니다. attachment와 함께 Content-Type: application/octet-stream을 설정하면 어떤 파일 형식이든 다운로드가 강제됩니다. 브라우저 확장 프로그램과 내장 뷰어(PDF.js)도 이 디렉티브를 무시할 수 있습니다.
다운로드를 기대했는데 인라인 표시가 일어납니다. Content-Disposition 헤더가 없으면 대부분의 콘텐츠 타입에서 기본값은 inline입니다. 다운로드를 유도하려면 서버가 attachment를 명시적으로 보내야 합니다. nginx에서는 해당 location 블록에 add_header Content-Disposition “attachment”; 를 추가하십시오. Apache에서는
filename과 filename의 우선순위. 두 매개변수가 모두 있으면 모든 최신 브라우저에서 filename이 우선합니다. filename을 지원하지 않는 구형 클라이언트는 filename으로 되돌아갑니다. 항상 두 매개변수를 모두 포함하십시오. filename 값은 특수 문자에 퍼센트 인코딩을 사용해야 합니다. filename*=UTF-8”na%C3%AFve.txt 처럼 씁니다.
프레임워크별 다운로드 응답 헬퍼. 대부분의 웹 프레임워크는 다운로드 헤더를 설정하는 내장 메서드를 제공합니다. Django는 as_attachment 매개변수와 함께 FileResponse를 사용합니다. Express는 res.download()를 사용합니다. Flask는 as_attachment=True와 함께 send_file()을 사용합니다. Rails는 disposition 옵션과 함께 send_data나 send_file을 사용합니다. 이들 메서드는 파일명 인코딩과 헤더 서식을 알아서 처리하여 수작업 실수를 줄여 줍니다.