"HTTP 메시지는 요청이든 응답이든 같은 기본 구조를 공유해. 이 구조를 한 번 익히면 낯선 메시지도 차근차근 읽을 수 있어."
한 가지 기본 구조
HTTP/1.1 메시지는 다음 네 부분을 순서대로 살펴보면 돼:
- 시작 줄 — 어떤 종류의 메시지인지 알려 주는 첫 줄.
- 헤더 — 0개 이상의 이름과 값 쌍.
- 빈 줄 — CRLF 하나로 이루어진 빈 줄이며, "헤더가 끝났다"는 경계 표시.
- 본문 — 선택적 페이로드. 비어 있을 수도 있고 JSON, 양식 데이터, 이미지, 이벤트 스트림처럼 다양한 형식을 담을 수도 있어.
HTTP/1.1 메시지를 읽을 때는 이 네 부분이 기본 틀이야. HTTP/2와 HTTP/3는 같은 의미를 이진 프레임으로 표현하므로 전송선의 모양은 달라지지만, 애플리케이션이 다루는 요청과 응답의 개념은 이어져. 먼저 이 틀을 익혀 두면 이후 내용은 구체적인 변주로 보일 거야.
시작 줄 — 요청과 응답을 가르는 첫 단서
HTTP/1.1에서 요청과 응답의 구조적 차이가 가장 선명하게 드러나는 곳이 첫 줄이야.
요청 시작 줄은 토큰 세 개로 이루어져: METHOD SP URI SP HTTP-VERSION. 예를 들어 POST /api/chat HTTP/1.1은 "HTTP/1.1을 사용해 /api/chat에 POST 요청을 보낸다"는 뜻이야.
응답 시작 줄도 토큰 세 개지만 구성은 달라: HTTP-VERSION SP STATUS-CODE SP REASON-PHRASE. 예를 들어 HTTP/1.1 201 Created는 "HTTP/1.1 응답이며 상태 코드는 201, 이유 문구는 Created"라는 뜻이야. 이유 문구(reason phrase)는 사람이 읽기 위한 설명이므로, 클라이언트의 분기 기준은 숫자 상태 코드여야 해.
헤더 — 메시지를 설명하는 메타데이터
헤더는 메시지의 성격과 처리 방법을 설명해. 필드 이름은 전송선에서 대소문자를 구분하지 않아 (Content-Type, content-type, CONTENT-TYPE은 모두 같은 필드야). 필드 값의 문법은 헤더마다 다르며, 쉼표로 여러 값을 결합할 수 있는지도 각 필드의 정의를 따라야 해.
처음에는 두 범주가 특히 중요해:
- 표현 메타데이터 — 본문이 무엇인지 설명해.
Content-Type,Content-Length,Content-Encoding이 대표적이며, 본문을 담은 요청과 응답 모두에 나타날 수 있어. - 처리 제어 정보 — 메시지를 어떻게 다룰지 알려 줘. 요청에서는
Host,Authorization,Accept,User-Agent를, 응답에서는Server,Set-Cookie,Cache-Control을 자주 만나.
빈 줄 — 단순하지만 꼭 필요한 경계
HTTP/1.1에서는 빈 줄 하나가 헤더 영역의 끝을 표시해. 이 줄을 빠뜨리면 서버는 뒤에 오는 데이터를 본문이 아니라 잘못된 헤더 줄로 해석할 수 있어. 대부분의 HTTP 클라이언트가 자동으로 넣어 주지만, TCP 연결에 요청을 직접 작성할 때는 자주 놓치는 부분이야.
Content-Type을 확인해. 본문의 형식을 알려 주는 계약이 바로 그 헤더에 있어. text/html 본문에 response.json()을 호출해 놓고 API가 잘못된 데이터를 보냈다고 오해하는 일이 아주 흔해.본문 — 선택적이며, 경계와 형식이 따로 정해져
본문은 선택 사항이야. GET 요청에는 보통 본문이 없고, DELETE 요청도 본문 없이 보내는 경우가 많아. HTTP/1.1에서는 Content-Length나 Transfer-Encoding: chunked 같은 장치가 본문의 경계를 알려 주며, 연결 종료가 경계가 되는 경우도 있어. HTTP/2와 HTTP/3에서는 프레임이 그 역할을 맡아. cwkPippa의 SSE 응답처럼 Transfer-Encoding: chunked를 사용하는 HTTP/1.1 응답도 기본 구조는 같고, 본문 데이터가 열린 연결을 통해 조금씩 도착한다는 점만 달라.
전체 구조를 눈에 익히기
이 네 부분을 전송된 순서대로 구분할 수 있으면, 처음 보는 HTTP/1.1 메시지도 침착하게 읽어낼 수 있어.