MIME 타입이 하는 일
MIME 타입(미디어 타입)은 종류/세부형식 꼴로 데이터의 성격을 알려 주는 문자열입니다. 브라우저는 확장자가 아니라 응답의 Content-Type 헤더를 보고 파일을 화면에 그릴지, 실행할지, 다운로드할지 정합니다. CSS를 text/plain으로 보내면 스타일이 적용되지 않고, 자바스크립트 모듈이나 WebAssembly는 타입이 틀리면 아예 로드가 거부됩니다. 반대로 사용자가 올린 파일을 text/html로 서빙하면 XSS 통로가 되므로 업로드 파일은 확장자가 아니라 내용(매직 바이트)으로 타입을 검사하고 X-Content-Type-Options: nosniff를 함께 보내는 것이 안전합니다. 조회는 브라우저 안에서만 이루어집니다.
charset과 파라미터
text/* 계열은 ; charset=utf-8을 붙여야 한글이 깨지지 않습니다. application/json은 규격상 항상 UTF-8이라 charset이 필요 없지만 붙여도 무해합니다. multipart/form-data는 boundary= 파라미터가 필수이며, fetch로 FormData를 보낼 때 Content-Type을 직접 지정하면 boundary가 빠져 서버가 파싱에 실패하므로 헤더를 브라우저에 맡겨야 합니다.
한글 파일명 다운로드
HTTP 헤더는 ASCII만 안전하게 실을 수 있습니다. RFC 6266/5987은 filename*=UTF-8''%ED%95%9C%EA%B8%80.pdf처럼 퍼센트 인코딩한 이름을 filename*에 넣고, 구형 클라이언트를 위해 ASCII 대체 이름을 filename=에 같이 두라고 정합니다. 현대 브라우저는 모두 filename*을 우선합니다. 예전 방식인 URLEncoder.encode 결과를 filename=에 그대로 넣거나 브라우저별로 분기하는 코드는 더 이상 필요 없습니다. 이 도구에 보고서.xlsx처럼 파일명을 통째로 넣으면 완성된 헤더를 만들어 줍니다.
표준과 비표준
IANA에 등록된 타입이 표준이고, x- 접두어가 붙거나 언어 소스 파일(text/x-python)에 쓰이는 것은 관행입니다. 비표준 타입도 브라우저는 대개 모르는 타입으로 취급해 다운로드로 처리하므로 큰 문제는 없지만, 같은 확장자를 두 가지로 표기하는 경우(audio/wav와 audio/x-wav)가 있어 서버 설정과 클라이언트 검사를 맞춰야 합니다. .ts처럼 타입스크립트와 MPEG-TS가 확장자를 공유하는 경우도 있습니다.
자주 묻는 질문
업로드한 파일의 MIME 타입이 브라우저마다 달라요.
File.type은 OS의 확장자 등록 정보에서 가져오기 때문에 환경마다 다르고 위조도 쉽습니다. 서버에서 파일 앞부분 바이트(매직 넘버)로 검사해야 합니다.
application/octet-stream은 언제 쓰나요?
타입을 모르거나 무조건 다운로드시키고 싶을 때입니다. 브라우저는 이 타입을 절대 화면에 렌더링하지 않습니다.
한글 파일(.hwp)의 MIME 타입은요?
공식 등록 타입은 없고 application/x-hwp 또는 application/haansofthwp가 관행적으로 쓰입니다. HWPX는 application/hwp+zip이 사용됩니다.