HTTPQUERY
한국어

Content-Type

사용법

Content-Type 헤더는 담긴 콘텐츠의 미디어 타입을 클라이언트에(요청 본문의 경우에는 서버에) 알립니다. 미디어 타입은 수신 측이 본문을 어떻게 파싱하고 렌더링할지를 결정합니다. 이 헤더가 없으면 클라이언트는 MIME 스니핑에 의존하게 되는데, 이는 보안 위험과 일관되지 않은 동작을 낳습니다.

참고

Accept는 클라이언트가 무엇을 받고 싶은지 선언합니다. Content-Type은 무엇을 보내는지 선언합니다. Accept는 요청에 나타납니다. Content-Type은 (본문이 있을 때의) 요청과 응답 양쪽에 나타납니다. GET 요청은 보통 본문이 없어 Content-Type이 필요 없습니다. 본문이 있는 POST와 PUT 요청에는 이 헤더가 필요합니다.

미디어 타입은 슬래시로 구분된 최상위 타입과 서브타입으로 구성되며, 선택적으로 매개변수가 뒤따릅니다. Accept 요청 헤더는 콘텐츠 협상 과정에서 Content-Type과 함께 작동하여, 서버가 하나를 선택하기 전에 클라이언트가 선호하는 미디어 타입을 표현할 수 있게 합니다.

서버와 중간 노드는 전송 전에 Content-Encoding(gzip이나 br 등)을 적용하기도 합니다. Content-Type 헤더는 언제나 인코딩 이전의 원래 미디어 타입을 기술하며, 인코딩된 형식을 기술하지 않습니다.

MIME-Version 헤더는 MIME 타입의 이메일 기원에서 유래했으며 일부 HTTP 메시지에 나타나지만, HTTP는 미디어 타입 처리에 이 헤더를 요구하지 않습니다.

media-type

미디어 타입 값은 IANA에 등록된 type/subtype 형식을 따릅니다. 흔한 타입으로는 text/html, application/json, image/png, application/octet-stream이 있습니다. 전체 레지스트리는 IANA가 관리합니다.

charset

charset 매개변수는 텍스트 기반 미디어 타입의 문자 인코딩을 지정합니다. 웹에서는 UTF-8이 지배적인 인코딩입니다.

Content-Type: text/html; charset=UTF-8

boundary

boundary 매개변수는 multipart/* 미디어 타입에 필수입니다. boundary 문자열은 multipart 본문의 각 파트를 구분합니다. boundary 값은 어떤 본문 파트 안에도 나타나서는 안 됩니다.

Content-Type: multipart/form-data; boundary=----FormBoundary

예시

서버가 UTF-8 인코딩의 HTML 페이지를 반환합니다. 브라우저는 미디어 타입을 보고 콘텐츠를 웹 페이지로 렌더링하고, charset을 보고 텍스트를 올바르게 디코딩합니다.

Content-Type: text/html; charset=UTF-8

API가 JSON 응답을 반환합니다. application/json 미디어 타입은 본문을 JSON으로 파싱하라고 클라이언트에 지시합니다.

Content-Type: application/json

API 오류 응답이 구조화된 problem details 페이로드임을 알리기 위해 application/problem+json 미디어 타입을 사용합니다.

Content-Type: application/problem+json

클라이언트가 Accept: text/markdown을 보내면 CDN이 HTML 페이지를 즉석에서 Markdown으로 변환합니다. 응답은 콘텐츠 타입으로 text/markdown을 담아 본문이 HTML이 아닌 Markdown임을 알립니다.

Content-Type: text/markdown; charset=utf-8

AI 에이전트와 Content-Type

Cloudflare 같은 CDN 공급자는 Content-Type: text/markdown과 함께 변환된 문서의 토큰 수를 추정한 x-markdown-tokens 헤더를 반환합니다. 에이전트는 콘텐츠 타입으로 올바른 파서를 고르고, 토큰 추정치로 컨텍스트 윈도 예산을 관리합니다.

파일 업로드는 요청 본문 안에서 폼 필드와 파일 데이터를 구분하는 boundary 문자열과 함께 multipart/form-data를 사용합니다.

Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW

서버가 바이너리 파일 다운로드를 전달합니다. application/octet-stream 타입은 원시 바이너리 데이터를 뜻하며, attachment로 설정된 Content-Disposition 헤더와 함께 쓰이는 경우가 많습니다.

Content-Type: application/octet-stream

multipart/byteranges 응답은 하나의 리소스에서 여러 바이트 범위를 전달합니다. 각 파트는 자체 Content-Type과 Content-Range 헤더를 가집니다.

Content-Type: multipart/byteranges; boundary=THIS_STRING_SEPARATES

문제 해결

렌더링 실패와 파싱 오류는 Content-Type 헤더가 없거나 잘못된 데서 비롯되는 경우가 많습니다.

charset 매개변수가 없어 텍스트가 깨집니다. charset이 선언되지 않으면 브라우저는 기본 인코딩(흔히 ISO-8859-1)으로 되돌아갑니다. 비ASCII 문자는 깨진 글자로 나타납니다. charset 매개변수를 명시적으로 추가하십시오. Content-Type: text/html; charset=UTF-8 처럼 씁니다. nginx에서는:

charset utf-8;

Apache에서는:

AddDefaultCharset UTF-8

Content-Type이 올바른데도 브라우저가 MIME 스니핑을 적용합니다. 브라우저는 선언된 타입을 무시하고 본문 콘텐츠를 스니핑해 타입을 판단하기도 합니다. 사용자가 업로드한 콘텐츠가 HTML로 제공될 때 이 동작은 XSS 공격 경로를 만듭니다. MIME 스니핑을 막으려면 X-Content-Type-Options 헤더를 nosniff로 설정해 추가하십시오.

X-Content-Type-Options: nosniff

API가 application/json 대신 text/html을 반환합니다. API에서 JSON을 파싱하는 클라이언트가 HTML 오류 페이지나 프레임워크 기본 응답을 받습니다. 이는 오류 핸들러나 리버스 프록시가 응답을 가로채 Content-Type을 갱신하지 않은 채 본문을 교체할 때 발생합니다. 오리진 서버, 애플리케이션 프레임워크, 리버스 프록시, CDN으로 이어지는 전체 응답 연쇄를 점검하십시오. Express.js에서는 res.json()을 호출하면 올바른 헤더가 자동으로 설정됩니다. Django에서는 HttpResponse 대신 JsonResponse를 반환하십시오.

multipart boundary 불일치로 파일 업로드가 깨집니다. Content-Type 헤더에 선언된 boundary 문자열은 요청 본문에서 사용된 구분자와 일치해야 합니다. 불일치하면 서버가 multipart 본문 파싱에 실패합니다. DevTools의 Network 탭에서 Headers와 Payload 섹션으로 원시 요청을 살펴보십시오. FormData 객체와 함께 fetch()나 XMLHttpRequest를 사용할 때는 boundary를 직접 설정하지 마십시오. 요청에서 Content-Type 헤더를 생략하면 브라우저가 올바른 boundary를 자동으로 생성합니다.

프레임워크 기본 Content-Type이 명시적 설정을 덮어씁니다. 일부 프레임워크는 애플리케이션 코드가 실행된 뒤에 Content-Type을 설정합니다. Express.js, Django, Spring Boot의 미들웨어가 헤더를 재설정할 수 있습니다. 미들웨어 실행 순서를 확인하십시오. Express.js에서는 헤더를 수정하는 모든 미들웨어 이후에 res.type()이나 res.set(‘Content-Type’, …)이 호출되도록 하십시오.

DevTools로 Content-Type 문제 진단하기. 브라우저 DevTools의 Network 탭을 열고 요청을 선택한 뒤 Response Headers 섹션에서 Content-Type 값을 살펴보십시오. 선언된 타입을 Response나 Preview 탭에 보이는 실제 본문 콘텐츠와 비교하십시오. 브라우저의 간섭 없이 명령줄에서 헤더를 확인하려면 curl -I https://example.re/api/data 를 사용하십시오.