HTTP 헤더는 용량 제한이 있을까?
API를 만들다 말고 갑자기 궁금해졌다. 그냥 헤더에 다 때려박으면 안 되나 싶어서 찾아본 김에 정리해둔다.
왜 궁금해졌나

API를 만드는 도중 Axios로 POST 요청을 보내는 과정에서, 왜 데이터를 헤더에 다 안 보내고 굳이 Body에 실어서 날릴까 의문이 들었다.
그냥 헤더에 다 때려박으면 안 될까 싶어서 찾아봤다. 아무래도 데이터 크기 이슈가 있지 않을까 싶었다.
스펙에는 제한이 없다
일단 정답부터 말하면 HTTP 스펙상 헤더의 크기 제한은 없다.
RFC를 뒤져봐도 “헤더는 몇 바이트까지”라는 문장은 나오지 않는다. 이론적으로는 헤더에 다 실어 보내도 프로토콜을 위반하는 게 아니라는 뜻이다.
그런데 엔진이 막는다
그런데 실제로는 우리가 사용하는 엔진에서 이를 제한하고 있다. 스펙에 없으니 각 구현체가 알아서 안전한 값을 정해둔 셈이다.
| 웹서버 / 런타임 | 기본 헤더 크기 제한 |
|---|---|
| Apache | 8 KB |
| Nginx | 4 ~ 8 KB |
| IIS | 8 ~ 16 KB |
| Tomcat | 8 ~ 48 KB |
| Node.js (< 13) | 8 KB |
| Node.js (≥ 13) | 16 KB |
대부분 8 KB 언저리에서 잘린다. 헤더에 데이터를 실어 보내는 설계는 결국 이 8KB 안에서만 성립한다는 얘기다.
게다가 값이 제각각이라는 것도 걸린다. 로컬 Node에서는 16KB까지 통과하던 요청이 앞단의 Nginx에서 4KB에 걸려 튕길 수도 있다. 그것도 애플리케이션 로그에는 아무것도 안 남은 채로 말이다.
그럼 제한을 풀면 되지 않나
엔진별로 헤더 크기를 바꿀 수 있고, 일부 엔진은 아예 제한을 풀 수 있는 기능을 제공한다. 다만 이건 권장되지 않는다.
제한되지 않은 HTTP 헤더 크기는 서버를 공격에 노출시키고 유기적 트래픽을 제공하는 용량을 감소시킬 수 있기에 추천하지 않는다.
거대한 헤더를 붙인 요청을 계속 던지는 것만으로 서버 메모리를 갉아먹을 수 있으니 그럴 만도 하다. 헤더는 요청을 라우팅하기 전에 전부 읽어야 하는 부분이라 중간에 걸러낼 방법도 마땅치 않다.
정리
| 구분 | 헤더 | Body |
|---|---|---|
| 스펙상 크기 제한 | 없음 | 없음 |
| 실제 제한 | 서버 구현이 8 KB 내외로 제한 | 서버 설정으로 MB 단위 조절 가능 |
| 제한 초과 시 | 400 / 431 로 거절 | 413 등 명확한 응답 |
| 용도 | 메타데이터 (인증, 콘텐츠 타입 …) | 실제 데이터 |
그러니까 처음 의문의 답은 이렇다. 데이터가 Body로 가는 건 그냥 관습이 아니라, 그래야만 해서였다.
마치며
“굳이 왜 이렇게 하지?” 싶은 것들은 대개 이유가 있고, 그 이유가 스펙이 아니라 구현체 쪽에 숨어 있는 경우도 많다는 걸 다시 확인했다.
스펙에 없으니 무제한인 게 아니라, 오히려 스펙에 없어서 각자 다르게 막아뒀다는 점이 좀 재밌었다. 8KB든 48KB든 서버마다 다르니, 헤더에 뭔가 큰 걸 싣는 설계는 결국 배포 환경을 타는 코드가 되어버린다.
다음엔 이런 걸 확인해보면 좋겠다.
- 직접 재보기 — 로컬에 Nginx를 띄우고 헤더 크기를 점점 키우며 몇 바이트에서 튕기는지 실측하기.
- HTTP/2의 HPACK — HTTP/2는 헤더를 압축한다. 그럼 이 제한은 압축 전 기준일까 후 기준일까.
- 쿠키가 헤더를 먹는 양 — 서드파티 스크립트가 쿠키를 잔뜩 심어두면 이 8KB를 실제로 얼마나 잡아먹는지.