Engineering note · HTTP

Content-Disposition으로 브라우저 표시와 다운로드 제어하기

2026년 07월 13일이현수
태그httpcontent-dispositiondownload

Content-Disposition의 inline과 attachment가 브라우저의 파일 처리 방식에 미치는 영향과 filename·filename* 사용법, 교차 출처에서 헤더를 읽을 때의 조건을 정리한다.

<object><embed>로 PDF를 표시하려고 했는데 브라우저가 파일을 바로 다운로드했다. 태그의 문제가 아니라 파일 응답에 설정된 Content-DispositionContent-Type이 원인이었다.

inline과 attachment의 차이

http
Content-Disposition: inline
Content-Disposition: attachment
Content-Disposition: attachment; filename="report.pdf"

inline은 응답을 미디어 타입에 맞게 기본 처리하라는 뜻이다. 브라우저가 해당 형식을 표시할 수 있다면 PDF 뷰어나 이미지 화면처럼 브라우저 안에서 처리한다. 헤더를 생략했을 때의 기본 처리와 가깝기 때문에 inline만으로 화면 표시를 강제하지는 않는다.

attachment는 응답을 현재 화면에서 처리하기보다 로컬 파일로 저장하도록 안내한다. filename을 함께 보내면 저장할 때 사용할 기본 파일명을 제안할 수 있다.

브라우저가 최종적으로 어떻게 처리할지는 Content-Disposition 하나로만 정해지지 않는다. Content-Type과 브라우저가 해당 미디어 타입을 표시할 수 있는지도 함께 영향을 준다.

object나 embed에 넣은 PDF가 다운로드된 이유

http
Content-Type: application/pdf
Content-Disposition: inline

PDF를 브라우저 안에서 표시하려면 응답이 PDF라는 사실과 화면에서 처리할 대상이라는 사실이 함께 전달돼야 한다. <object><embed>는 응답 헤더를 덮어쓰지 않는다.

응답에 Content-Disposition: attachment가 설정돼 있으면 브라우저는 PDF 뷰어보다 저장 동작을 우선한다. Content-Disposition: inline이어도 Content-Type: application/octet-stream처럼 범용 바이너리 타입을 보내면 브라우저가 PDF로 판단하지 못해 다운로드할 수 있다.

스토리지 URL을 직접 사용한다면 객체 메타데이터도 확인해야 한다. 애플리케이션 코드에서 <object>를 바꾸는 것보다 저장소가 반환하는 Content-TypeContent-Disposition을 바로잡는 것이 우선이다.

한글 파일명은 filename*으로 전달

http
Content-Disposition: attachment;
  filename="report.pdf";
  filename*=UTF-8''%EB%B3%B4%EA%B3%A0%EC%84%9C.pdf

filename은 오래된 클라이언트에서도 사용할 수 있는 기본 파일명이다. 한글처럼 ASCII 범위를 벗어나는 문자는 filename*에 UTF-8과 퍼센트 인코딩을 사용해 전달한다.

두 값이 함께 있으면 filename*을 지원하는 클라이언트는 해당 값을 우선하고, 지원하지 않는 클라이언트는 filename을 대체 값으로 사용한다. 호환성을 고려할 때 filename을 먼저 두고 filename*을 뒤에 두는 게 좋다.

프론트엔드에서 응답 헤더를 읽을 때

ts
const response = await fetch(fileUrl)
const disposition = response.headers.get('Content-Disposition')

같은 출처의 응답이라면 Headers에서 값을 읽을 수 있다. 다른 출처에 요청할 때는 Content-Disposition이 CORS 안전 목록에 포함되지 않으므로 서버가 이 헤더를 명시적으로 노출해야 한다.

http
Access-Control-Expose-Headers: Content-Disposition

이 설정이 없으면 네트워크 응답에 헤더가 보여도 JavaScript에서 response.headers.get()을 호출했을 때 null이 나온다. 인증 정보를 포함한 요청에서는 와일드카드보다 읽을 헤더 이름을 직접 나열하는 게 확실하다.

multipart/form-data의 Content-Disposition

http
Content-Disposition: form-data; name="attachment"; filename="report.pdf"

HTTP 응답 헤더의 Content-Disposition은 응답 본문을 표시하거나 저장하는 방식을 설명한다. multipart/form-data의 각 파트에 들어가는 Content-Disposition은 폼 필드의 이름과 업로드한 파일 정보를 나타낸다. 이름은 같지만 적용 위치와 목적이 다르므로 구분해야 한다.

참고한 페이지