Content-Length
사용법
Content-Length 헤더는 HTTP 메시지 본문의 정확한 바이트 크기를 전달합니다. 클라이언트는 이 값을 근거로 응답을 모두 수신한 시점을 파악하며, 덕분에 HTTP/1.1의 지속 커넥션에서 해당 커넥션을 재사용할 수 있게 됩니다.
서버가 본문 크기를 아는 상태로 응답을 보내면, Content-Length 헤더 덕분에 클라이언트는 적절한 양의 메모리를 할당하고 다운로드 중 정확한 진행률을 표시할 수 있습니다. 선언된 길이와 실제 본문 크기가 어긋나면 전송이 잘렸거나 손상되었다는 신호입니다.
이 헤더는 chunked Transfer-Encoding과 상호 배타적입니다. 서버가 크기를 알 수 없는 응답을 스트리밍할 때는 고정된 콘텐츠 길이 대신 chunked 인코딩이 사용됩니다. HTTP/2와 HTTP/3에서는 프레이밍이 프로토콜 수준에서 메시지 경계를 처리하지만, Content-Length는 본문 크기 검증 용도로 여전히 유효합니다.
값은 메시지 본문의 옥텟(바이트) 수를 나타내는 하나의 음수가 아닌 정수입니다.
예시
서버가 3,495바이트의 JSON 응답을 반환합니다. 클라이언트는 정확히 3,495바이트를 읽은 뒤 메시지가 완료된 것으로 간주합니다.
Content-Length: 3495
POST 요청이 폼 본문을 전송합니다. Content-Length 헤더는 요청 본문에서 몇 바이트를 기대해야 하는지 서버에 알려 줍니다.
POST /submit HTTP/1.1
Host: example.re
Content-Type: application/x-www-form-urlencoded
Content-Length: 27
field=value&other=something
chunked 전송 인코딩을 사용하는 응답은 Content-Length 헤더를 아예 생략합니다. Transfer-Encoding 헤더가 우선합니다.
Transfer-Encoding: chunked
문제 해결
전송 실패와 커넥션 오류는 잘못되었거나 서로 충돌하는 Content-Length 값에서 비롯되는 경우가 많습니다.
전송이 중단되거나 부분 다운로드로 끝납니다. 클라이언트가 Content-Length에 선언된 것보다 적은 바이트를 수신하고 응답이 잘렸다고 보고합니다. 흔한 원인은 오리진이 커넥션을 일찍 닫거나, 프록시 타임아웃이 전송을 끊거나, 서버가 본문 크기를 잘못 계산하는 경우입니다. curl -v https://example.re/file 을 실행하여 Content-Length 헤더 값과 실제 수신된 바이트 수(전송 요약에 표시됨)를 비교하십시오. 값이 어긋나면 문제가 확인된 것입니다.
chunked 인코딩과 Content-Length가 함께 존재합니다. 같은 응답에 Transfer-Encoding: chunked와 Content-Length를 모두 보내는 것은 HTTP 명세 위반입니다. 클라이언트는 Transfer-Encoding이 있으면 Content-Length를 무시해야 하지만, 모든 구현이 이 규칙을 따르지는 않습니다. chunked 인코딩을 사용할 때는 Content-Length를 제거하십시오. nginx에서는 본문 크기를 알 수 없을 때 chunked 인코딩이 자동으로 적용되며, 그 경우 nginx는 Content-Length를 생략합니다. 두 헤더를 모두 설정하는 사용자 정의 애플리케이션 코드나 미들웨어는 수정해야 합니다.
미들웨어가 본문을 수정한 뒤 Content-Length가 틀어집니다. 콘텐츠를 주입하는 미들웨어(분석 스크립트, 보안 토큰, 디버그 툴바)는 Content-Length를 갱신하지 않은 채 본문 크기를 바꿉니다. 그 결과 브라우저가 보이는 콘텐츠를 잘라 내거나, 결코 도착하지 않을 바이트를 기다립니다. 모든 본문 수정이 끝난 마지막 단계로 Content-Length 계산을 옮기십시오. Express.js에서는 compression 미들웨어가 이를 자동으로 처리합니다. 직접 구성한 환경에서는 Content-Length를 제거하고 대신 chunked 인코딩에 의존하십시오.
HEAD 응답이 잘못된 Content-Length를 담고 있습니다. HEAD 응답은 대응하는 GET 응답이 담았을 Content-Length와 동일한 값을 포함하되 본문은 없어야 합니다. 일부 프레임워크는 Content-Length가 0인 HEAD 응답을 생성하거나 헤더를 아예 생략합니다. curl -I https://example.re/resource (HEAD)와 curl -s -o /dev/null -w ’%{size_download}’ https://example.re/resource (GET 본문 크기)를 비교하여 확인하십시오. 값이 어긋나면 리소스 크기 파악에 HEAD를 사용하는 다운로드 관리자와 캐싱 프록시가 망가집니다.
curl로 Content-Length 문제 진단하기. curl -v https://example.re/resource 를 실행하면 상세 출력에서 Content-Length 헤더와 전송된 바이트 수를 볼 수 있습니다. Content-Length: N 줄은 선언된 크기를 보여 줍니다. 끝부분의 bytes received는 실제 전송량을 보여 줍니다. -o /dev/null 을 추가하면 본문을 버리고 헤더에 집중할 수 있습니다. 압축된 응답에서는 Content-Length가 원본 크기가 아니라 압축된 크기를 반영한다는 점을 기억하십시오.