웹 기초 ·
Content-Type이 데이터의 포장 라벨이 되는 이유
먼저 답부터
Content-Type은 HTTP 본문이 어떤 종류의 데이터인지 알려 주는 헤더입니다. 응답에서는 브라우저가 HTML, JSON, 이미지 등을 알맞게 처리하도록 돕고, 요청에서는 서버가 받은 본문을 어떤 형식으로 읽을지 알려 줍니다. 주소나 파일 이름만 믿지 말고 실제 헤더와 본문이 서로 맞는지 확인해야 합니다.
웹페이지가 열리는데 글 대신 파일이 내려받아지거나, API에 JSON을 보냈는데 서버가 지원하지 않는 형식이라고 거절할 때가 있습니다. 이때 주소와 본문만 보지 말고 HTTP 헤더에 적힌 Content-Type을 함께 확인해야 합니다.
택배 상자 안에 종이, 유리병, 옷이 들어 있어도 겉에 아무 표시가 없으면 받는 사람이 어떻게 다룰지 바로 판단하기 어렵습니다. Content-Type은 본문이라는 상자에 붙은 포장 라벨과 비슷합니다. 라벨과 실제 내용물이 맞아야 브라우저와 서버가 같은 방식으로 처리할 수 있습니다.
HTTP 헤더는 본문 앞에 붙는 설명표다
HTTP 메시지는 요청이나 응답의 상태를 설명하는 헤더와 실제로 전달할 내용인 본문으로 나눠 볼 수 있습니다. 헤더는 누가 읽을 수 있는 형식인지, 압축됐는지, 얼마나 오래 보관할지 같은 부가 정보를 이름과 값의 쌍으로 전달합니다. 본문은 HTML 문서, JSON 데이터, 이미지 파일처럼 실제 내용입니다.
헤더는 화면에 보이는 글의 첫 문단이 아닙니다. 식당 주문서에서 메뉴 이름과 조리 주의 사항이 음식 자체와 다른 것처럼, 헤더는 본문을 설명하지만 본문을 대신하지 않습니다. 개발자 도구 Network에서 요청 하나를 누르면 Headers와 Response가 따로 보이는 이유입니다.
Content-Type은 데이터 종류와 처리 방식을 알린다
RFC 9110은 Content-Type이 메시지에 담긴 표현의 미디어 타입을 나타내며, 받는 쪽이 데이터 형식과 처리 방식을 판단하게 한다고 설명합니다. 미디어 타입은 보통 큰 종류와 세부 종류를 빗금으로 나눠 씁니다. 문자 자료에는 인코딩을 알리는 charset 같은 매개변수가 붙을 수 있습니다.
text/html은 HTML 문서, application/json은 JSON 데이터, image/png는 PNG 이미지를 뜻합니다. text/html; charset=utf-8은 HTML 문자 자료를 UTF-8 방식으로 읽으라는 정보까지 담습니다. 확장자가 .json처럼 보인다고 자동으로 JSON이 되는 것은 아니며, HTTP로 받은 자원은 실제 응답 헤더와 내용이 맞는지 봐야 합니다.
요청과 응답에서 같은 이름의 방향이 달라진다
응답의 Content-Type은 서버가 돌려준 본문이 무엇인지 클라이언트에 알립니다. 브라우저는 이 정보를 바탕으로 HTML을 문서로 처리하고, CSS를 스타일로 적용하며, 이미지를 그림으로 표시합니다. API 응답이 JSON이면 프로그램은 JSON 문법으로 읽을 준비를 합니다.
요청의 Content-Type은 반대 방향입니다. 브라우저나 앱이 서버로 보내는 본문이 어떤 형식인지 알려 줍니다. 로그인 정보를 JSON으로 보내면서 application/json을 붙였다면 서버는 JSON 해석기로 본문을 읽을 수 있습니다. 하지만 라벨만 JSON이고 본문 문법이 틀리면 여전히 실패합니다. Content-Type은 내용의 진실성이나 안전성을 보장하는 검사표가 아닙니다.
짧은 메시지 한 쌍을 읽어 본다
다음은 JSON 본문을 보내고 받는 흐름을 단순화한 예시입니다.
POST /api/profile HTTP/1.1
Content-Type: application/json
{"nickname":"nupcoder"}
서버가 같은 종류의 결과를 돌려준다면 응답에도 별도의 Content-Type이 붙습니다.
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{"saved":true}
첫 번째 라벨은 서버가 요청 본문을 읽는 방법이고, 두 번째 라벨은 클라이언트가 응답 본문을 읽는 방법입니다. 두 줄의 이름은 같지만 서로 다른 메시지에 속하므로 한쪽을 고쳤다고 다른 쪽까지 자동으로 바뀌지는 않습니다.
Accept와 Content-Encoding은 다른 질문에 답한다
Content-Type과 비슷해 보이는 헤더를 한 덩어리로 외우면 오류를 잘못 고치기 쉽습니다. Accept는 클라이언트가 어떤 응답 형식을 받을 수 있거나 선호하는지 알리는 요청 헤더입니다. Content-Type은 지금 실제로 보내는 본문의 형식을 설명합니다. 메뉴에서 먹을 수 있는 음식을 말하는 것과 식탁에 놓인 접시가 무엇인지 말하는 차이에 가깝습니다.
Content-Encoding은 gzip이나 Brotli처럼 본문에 추가로 적용된 압축 방식을 설명합니다. RFC 9110은 먼저 Content-Encoding을 풀어야 Content-Type이 가리키는 원래 데이터 형식을 얻는 두 단계 구조로 설명합니다. JSON인지 HTML인지와 압축됐는지는 서로 다른 문제입니다.
415 오류는 형식 협의부터 확인한다
서버가 요청 본문 형식을 지원하지 않으면 415 Unsupported Media Type으로 거절할 수 있습니다. 이때 무작정 요청을 반복하기보다 API 공식 문서, 요청 헤더, 실제 본문을 나란히 봅니다. 서버가 JSON을 요구하는데 폼 데이터나 일반 문자열을 보냈는지, Content-Type을 빠뜨렸는지, 라벨만 JSON이고 본문은 다른 모양인지 확인합니다.
파일 업로드에 자주 쓰는 multipart/form-data에는 각 부분을 나누는 boundary 정보가 필요합니다. 브라우저나 사용하는 라이브러리가 이 경계를 만들도록 설계된 경우 임의 문자열로 덮어쓰지 마세요. 결제나 회원 정보 API에서 시험할 때는 운영 요청을 반복하지 말고 문서의 테스트 환경과 가짜 값을 사용합니다.
브라우저의 추측은 설정 오류를 숨길 수 있다
서버가 Content-Type을 빠뜨리거나 실제 내용과 다른 값을 보내면 일부 브라우저는 앞부분을 살펴 형식을 추측하는 MIME 스니핑을 할 수 있습니다. WHATWG 표준은 파일 확장자가 신뢰하기 어렵고, 잘못된 추측이 업로드 파일을 HTML처럼 실행하게 만드는 보안 문제로 이어질 수 있다고 설명합니다.
그래서 서버는 자원마다 올바른 Content-Type을 보내고, 필요하면 X-Content-Type-Options: nosniff로 선언한 형식을 그대로 따르도록 합니다. 화면이 깨졌다고 이 보안 헤더부터 지우거나 브라우저 보호 기능을 끄지 마세요. 먼저 문제가 난 자원의 응답 헤더와 실제 파일 종류를 맞추고, 사용자 업로드 파일은 별도 저장 위치와 다운로드 정책을 포함해 서버 쪽 검증을 받아야 합니다.
오늘 바로 해볼 작은 실습
코드를 바꾸지 않고 공개 웹사이트 한 곳의 응답 헤더를 10분 동안 읽어 봅니다.
- 로그인과 결제가 필요 없는 공개 페이지를 엽니다.
- 개발자 도구 Network 탭을 열고 페이지를 새로고침합니다.
- 가장 위의 문서 요청을 눌러 Response Headers의 Content-Type을 적습니다.
- 이미지 요청 하나를 골라 Content-Type이
image/로 시작하는지 봅니다. - JavaScript나 CSS 요청 하나를 골라 확장자와 Content-Type이 어울리는지 비교합니다.
- 요청 헤더의 Accept와 응답 헤더의 Content-Type을 서로 다른 칸에 적습니다.
- Content-Encoding이 있다면 데이터 종류가 아니라 압축 방식이라고 표시합니다.
- Authorization, Cookie, 토큰, 이메일 같은 값은 복사하거나 공유하지 않습니다.
- 헤더 수정, 요청 재전송, 파일 다운로드, 보안 기능 해제는 이번 실습에서 하지 않습니다.
마지막으로 문서, 이미지, 스크립트 각각에 “보낸 형식”, “받은 형식”, “압축 여부”를 구분해 적어 보세요. 화면 오류를 만났을 때 상태 코드만 보는 데서 멈추지 않고, 어떤 본문이 어떤 라벨로 전달됐는지 설명할 수 있으면 첫 진단이 끝납니다.
확인한 자료
- RFC 9110 HTTP Semantics — RFC Editor
- MIME Sniffing Standard — WHATWG
- Content-Type header — MDN Web Docs
함께 읽기
- 주소를 입력하면 웹페이지가 열리는 과정을 주문 배달처럼 이해하기
웹 주소를 입력하면 브라우저는 DNS로 서버 주소를 찾고 HTTP 요청을 보냅니다. 서버가 돌려준 HTML, CSS, JavaScript와 이미지를 조합해 화면을 그리며, 404나 500 오류가 보이면 이 요청과 응답 중 실패한 구간을 확인하면 됩니다.
- 프론트엔드와 백엔드와 데이터베이스를 식당 역할로 구분하기
프론트엔드는 사용자가 보고 누르는 화면, 백엔드는 요청과 규칙을 처리하는 보이지 않는 부분, 데이터베이스는 회원과 주문 같은 기록을 보관하는 곳입니다. 식당으로 비유하면 각각 홀, 주방, 장부에 해당하며 세 역할이 연결돼 하나의 기능이 완성됩니다.
- API와 JSON을 메뉴판과 주문서처럼 읽는 첫 연습
API는 다른 서비스에 정해진 방식으로 기능이나 데이터를 요청하는 연결 창구이고, JSON은 그 요청과 답을 이름과 값의 묶음으로 적는 형식입니다. 메뉴판에서 가능한 주문을 확인하고 주문서에 항목을 적는 과정으로 생각하면 두 개념을 함께 이해하기 쉽습니다.