김영한님의 모든개발자를 위한 HTTP 웹 기본 지식을 수강 후 해당 내용을 기반으로 작성한 글입니다.
HTTP 헤더
- HTTP 프로토콜에서 클라이언트와 서버 간의 요청(request) 및 응답(response)에 대한 부가 정보를 전달하는 부분
- key: value 형식의 문자열
- 메시지 바디의 내용, 크기, 압축, 인증, 요청 클라이언트, 서버 정보, 캐시 관리 정보 등 많은 정보가 담겨 있음
RFC2616 (과거)
| 헤더 종류 | 사용처 | 예시 필드 |
|---|
| 요청 헤더 | 클라이언트 → 서버 | Host, User-Agent, Accept, Cookie |
| 응답 헤더 | 서버 → 클라이언트 | Content-Type, Set-Cookie, Cache-Control |
| 일반 헤더 | 양쪽 모두 | Connection, Date |
| 엔터티 헤더 | 본문 메타데이터 | Content-Type, Content-Length, Last-Modified |
| 확장 헤더 | 사용자 정의 및 특정 애플리케이션용 헤더 | X-Forwarded-For, X-Requested-With |
- 요청 헤더 (Request Headers)
클라이언트가 서버로 요청을 보낼 때 추가하는 정보
GET /index.html HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0
Accept: text/html
- 응답 헤더 (Response Headers)
서버가 클라이언트에 응답할 때 추가하는 정보
HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
Content-Length: 1234
Set-Cookie: sessionId=abc123; Path=/
Cache-Control: no-cache
- 일반 헤더 (General Headers)
요청과 응답에 모두 사용될 수 있는 헤더
- 엔터티 헤더 (Entity Headers)
요청이나 응답 본문에 대한 정보(메타 데이터)를 제공하며 메시지 본문은 엔티티 본문을 전달하는 데 사용된다.
엔티티 본문은 요청이나 응답에서 전달할 실제 데이터이며 엔티티 헤더는 본문의 데이터를 해석할 수 있는 정보를 제공한다.
RFC723x 변화
- 엔티티(Entity) 👉 표현 (Representation)
- 표현 = 표현 메타 데이터 + 표현 데이터
HTTP BODY
- 메시지 본문(message body)을 통해 표현 데이터 전달
- 메시지 본문 = 페이로드 (payload)
- 표현은 요청이나 응답에서 전달할 실제 데이터
- 표현 헤더는 표현 데이터를 해석할 수 있는 정보 제공(길이, 압축 정보, 유형 등)
🧐 표현(representation)이라고 하는 이유는?
HTTP의 리소스 표현 방식이 다양하기 때문!
HTTP는 리소스(Resource) 중심의 프로토콜이며 리소스란 웹 상의 모든 데이터나 객체를 의미한다. 여기서, 리소스 그 자체가 네트워크를 통해 전송되는 것이 아니라 리소스의 표현(Representation) 이 전송 된다.
즉, 표현이란 리소스를 네트워크를 통해 주고받기 위해 어떤 형식(포멧)으로 표현한 데이터를 말한다.
표현 헤더
표현 헤더는 요청, 응답에 모두 쓰인다.
표현 헤더 필드
- Content-Type: 표현 데이터 형식(미디어 타입, 문자 인코딩)
- application/json, text/html
- 예: Content-Type: text/html; charset=UTF-8
- Content-Encoding: 표현 데이터의 인코딩된 방식 (gzip, deflate)
- 데이터를 읽는 쪽에서 인코딩 헤더의 정보로 압축 해제
- 데이터를 전달하는 곳에서 압축 후 인코딩 헤더 추가
- Content-Language: 표현 데이터의 자연 언어 (ko, en)
- Content-Length: 표현 데이터의 길이(바이트 단위)
협상(contents Negotiation)
클라이언트와 서버가 통신 중에 가장 적합한 리소스 표현(Representation)을 결정하는 과정을 의미
협상 헤더는 요청시에만 사용한다.
- Accept: 클라이언트가 선호하는 미디어 타입을 전달
- Accept-Charset: 클라이언트가 선호하는 문자 인코딩
- Accept-Encoding: 클라이언트가 선호하는 압축 인코딩
- Accept-Language: 클라이언트가 선호하는 자연 언어
🧐 우선순위 언어를 서버에서 지원하지 않는다면?
👉 Quality Values(q) 값을 사용한다.
- 0 ~ 1 사이의 수로 표현, 클수록 높은 우선순위(1이 가장 높은 우선순위가 된다)
- 1은 생략한다
- Accept-Language: ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7
- ko-KR (q=1 생략)
- ko;q=0.9
- en-US;q=0.8
- en;q=0.7
협상은 구체적인 것이 우선이 된다.
- Accept: text/, text/plain, text/plain;format=flowed, /*
- text/plain;format=flowed
- text/plain
- text/*
- /
구체적인 것을 기준으로 미디어 타입을 맞춘다.
- Accept: text/;q=0.3, text/html;q=0.7, text/html;level=1,
text/html;level=2;q=0.4, /*;q=0.5

헤더 전송 방식
단순 전송
- content의 길이 값을 알고 있을 때, 그에 대한 정보를 제공
- 예: content-Length: 3433
압축 전송
- 서버에서 압축하여 전송하는 방식
- Content-Encoding 정보를 추가적으로 제공한다.
- Content-Encoding: gzip
분할 전송
- 덩어리를 쪼개서 분할하여 전송하는 방식
- 용량이 큰 바디를 쪼개서 전송하여 응답/요청을 기다리는 시간을 단축
- Transfer-Encoding: chunked
- 분할해서 보내기 때문에 Content-Length는 없다.
범위 전송
- 요청이 끊겨 중간부터 다시 전송해야하는 상황에서 유용
- 범위를 지정하여 보내는 방식
- Content-Range: bytes 1001-2000/2000
일반 정보
From
- 유저 에이전트의 이메일 정보를 포함
- 검색 엔진과 같은 곳에서 주로 사용하지만 실무에서는 잘 사용하지 않음
referer
- 현재 요청된 페이지의 이전 페이지 주소
- referrer의 오타이지만 표준이 되었다.
- 유입 경로를 분석할 때 많이 사용된다.
- 요청에서 사용된다.
user-agent

- 클라이언트의 애플리케이션 정보(사용자의 웹브라우저 정보와 같은)
- 어떤 종류의 브라우저에서 장애가 발생하는지 파악할 수 있음
- 요청에서 사용된다.
Server
- 요청을 처리하는 origin 서버의 소프트웨어 정보
- 응답에서 사용
- http 요청은 중간에 여러 프록시 서버를 거치게 되는데, 최종 서버를 origin 서버라고 한다. 이 origin 서버에 대한 정보
Date
- 응답에서만 사용
- 과거에는 요청에서도 사용되었지만 최신 스펙이서는 응답에서만 사용되도록 변경되었음
Host
- HTTP 요청에서 대상 서버의 도메인 이름과 포트 번호를 명시하는 헤더
- 요청에서 사용되는 필수 헤더
- 하나의 IP 주소나 서버가 여러 개의 도메인(호스트)을 제공하여 가상 호스팅이 가능하게 한다.
가상호스팅이란?
하나의 서버가 여러 개의 도메인(웹사이트)을 동시에 호스팅하는 기술
여러 개의 웹사이트를 하나의 서버에서 운영할 때, 서버는 Host 헤더를 기반으로 요청된 웹사이트를 식별할 수 있게 한다.
Location
- 페이지 리다이렉션
- 서버에서 3xx 응답의 결과로 Location 헤더가 있으면 그 위치로 자동으로 위치한다.
- 201으로 응답한다면 Location 값은 요청에 의해 생성된 리소스 URI이다.
- 3xx 응답의 Location은 요청을 자동으로 리다이렉션 하기 위한 대상 리소스를 가르킨다.
Allow
- 서버가 허용하는 HTTP 메서드 목록을 나타냄
- 요청된 Url은 존재하지만, 사용된 메서드가 허용되지 않은 경우 405 상태코드와 함께 Allow 헤더를 반환한다.
- 예: Allow: GET, POST, PUT
Retry-After
- 유저 에이전트가 다음 요청 하기까지 기다려야 하는 시간
- 서버가 일시적으로 다운되거나 유지보수 중일 때 503 코드와 함께 사용된다.
- 초 단위로 표현 가능
인증 헤더
Authorization
클라이언트 인증 정보를 서버에 전달
- Authorization: Basic xxxxxxxxxxxxxxxx
WWW-Authenticate
- 리소스 접근시 필요한 인증 방법을 정의
- 401 상태코드와 함께 해당 헤더를 사용
쿠키 (Cookie)
- set-Cookie: 서버에서 클라이언트로 쿠키를 전달할 때(응답)
- Cookie: 클라이언트가 서버에서 받은 쿠키를 저장하고, HTTP 요청시 서버로 전달
🧐 쿠키가 필요한 이유?
HTTP는 무상태 프로토콜이다. 이는 클라이언트가 요청할 때마다 서버는 이전 요청을 기억하지 못함을 의미한다. 즉, 클라이언트와 서버는 서로 상태를 유지하지 않는다. 따라서 로그인과 같이 특정 정보의 유지가 필요할 때, 쿠키를 사용하여 클라이언트 측에 저장하여 이를 HTTP 요청할 때 마다 헤더를 통해 서버로 전달한다.
쿠키의 사용
- 주 사용처는 사용자 로그인, 광고 정보 트래킹
- 쿠키 정보는 항상 서버에 전송되기 때문에 네트워크 추가 트래픽이 유발된다. 따라서 세션 id, 인증 토큰과 같은 최소한의 정보만 사용한다.
- 서버에 전송하지 않고, 웹 브라우저 내부에 저장하고 싶다면 웹 스토리지를 참고하자
쿠키의 생명주기
- Set-Cookie: expires=Sat, 26-Dec-2020 04:39:21 GMT - 만료일이 되면 삭제
- Set-Cookie: max-age=3600 (3600초) - 0이나 음수를 지정하면 쿠키 삭제
- 세션 쿠키: 만료 날짜를 생략하면 브라우저 종료 전까지 유지
- 영속 쿠키: 만료 날짜를 입력하면 해당 날짜까지 유지
쿠키의 도메인
- 쿠키의 도메인을 명시하게 되면 명시한 문서 기준 도메인과 서브 도메인을 포함하여 전송한다.
- 쿠키의 도메인을 생략하면 현재 문서 기준의 도메인만 적용된다. (하위 도메인은 접근 불가능)
예: example.org이 도메인이라면,
example.org - 쿠키 접근
dev.example.org - 쿠키 미접근
쿠키의 경로(path)
- 경로를 포함한 하위 페이지만 쿠키를 접근할 수 있다.
- 일반적으로 루트(
/)를 지정
쿠키의 보안
- Secure : https인 경우에만 쿠키를 전송
- HttpOnly: XSS 공격을 방지하고 자바스크립트에서 접근 불가능하며 HTTP 전송에서만 사용 가능
- SameSite: XSRF 공격을 방지하여 현재 요청하는 도메인과 쿠키에 설정된 도메인이 같은 경우에만 쿠키를 전송
캐시 (Cache)
캐시가 없다면?
- 데이터가 변경되지 않아도 계속 요청/응답하여 데이터를 전송 받아야 한다.
- 인터넷 네트워크는 매우 느리고 비싼데, 해당 비효율은 네트워크에 좋지 않은 영향
- 불필요한 브라우저 로딩을 하게되며 이로 인해 로딩 속도가 느려질 수 있다.
- 느린 사용자 경험으로 이어짐
캐시를 적용한다면?
- 캐시 가능한 시간동안은 네트워크를 사용하지 않아도 된다.
- 불필요하게 재전송 받지 않아 네트워크 사용량을 줄이며 로딩 속도가 개선된다.
- 빠른 사용자 경험
캐시가 시간 초과 된다면?
- 서버를 통해 데이터를 다시 조회하고, 캐시를 갱신한다.
- 이 때 다시 네트워크 다운로드가 발생
캐시 만료 후에도 서버 데이터를 변경하지 않으려면?
- 클라이언트의 데이터와 서버의 데이터가 변경되지 않고 일치하다는 사실을 검증하는 방법이 필요하다.
👉 검증 헤더를 추가하자.
캐시 검증 헤더
- Last-Modified
- 데이터가 마지막에 수정된 시간을 의미
- 클라이언트에서 요청할 때 if-modified-since라는 요청 헤더를 붙여 서버에 요청하여 서버에서 검증
- 서버에서 날짜가 일치하다면 바디를 전송하지 않고
304 (not modified)상태코드와 함께 헤더만 보내 응답한다.
- 클라이언트는 캐시를 불러와서 재사용한다.
- 변경이 됐다면, 200 상태 코드와 함께 바디를 포함한 모든 데이터를 다시 전송한다.
👉 검증 헤더(Last-Modified)와 조건부 헤더(if-modified-since)를 같이 사용한 것.
이점은?
- 바디에 해당하는 사이즈 용량을 줄여서 응답 보낼 수 있다.
- 네트워크 부하 감소
- 결과적으로 네트워크 다운로드가 발생하지만 용량이 적은 헤더 정보만 다운로드 가능해짐
Last-Modified와 if-modified-since의 단점
- 1초 미만 단위의 캐시 조정이 불가능
- 날짜 기반의 로직을 사용하기 때문에 최종적으로 수정된 데이터가 결국 수정이 되지 않은 경우, 날짜는 갱신이 되었기 때문에 데이터는 원본이랑 같지만 새로운 버전으로 인식하게 되는 허점이 있음.
- 서버에서 별도의 캐시 로직을 따로 관리하고 싶은 경우에는 적용할 수 없다.
개선방법은?
👉 ETag, If-None-Match
- 캐시용 데이터에 임의의 고유한 버전 이름을 적용
- 데이터가 변경되면 이 이름을 바꾸어 버전을 관리 (Hash 알고리즘을 사용하여 이름을 관리할 수 있다)
- 파일을 해쉬 알고리즘에 넣어서 반환된 해쉬 값이 같다면 - 동일한 데이터
- 클라이언트는 ETag 만 서버에 요청, 서버의 값과 같으면 유지, 다르면 다시 받는다.
- 캐시 제어 로직을 서버에서 완전히 관리하기 때문에 클라이언트는 캐시 메커니즘을 완전 모르게 됨(블랙박스)
캐시 제어 헤더 - Cache-Control
- max-age: 캐시 유효 시간, 초 단위
- no-cache: 데이터는 캐시가 가능하지만 항상 origin 서버에서 검증하고 사용한다.
- no-store: 데이터에 민감한 정보가 있기 때문에 저장하면 안된다.
프록시 캐시
- 클라이언트와 서버 사이에 위치한 중간 캐시 서버
- 프록시 서버는 클라이언트가 요청한 리소스를 대신 가져오고 저장한 뒤, 동일한 요청이 발생되면 저장된 데이터를 반환하여 네트워크 부하를 줄이는 역할을 하며 동시에 성능도 향상된다.
- CDN과 같은 글로벌 캐시 서버를 사용하면 origin 서버(원본 서버)가 멀리 떨어져 있는 경우에도 네트워크 왕복 시간을 줄여 더 빠른 응답이 가능
왜 프록시 캐시를 사용하면 성능이 향상될까?
- 네트워크 왕복 시간(RTT) 감소: 클라이언트가 원본 서버 대신 가까운 프록시 캐시에서 데이터를 가져오므로 네트워크 지연 시간이 줄어든다.
- 서버 부하 감소: 동일한 요청을 원본 서버에 보내지 않고 캐시에서 처리하므로 서버 리소스를 절약한다.
👉 즉, 프록시 캐시는 클라이언트와 서버 사이에 위치한 중간 캐시 서버로, 프록시 서버의 캐싱 기능을 의미한다. 프록시 서버는 클라이언트가 요청한 리소스를 대신 가져와 저장하고, 동일한 요청이 발생하면 캐시된 데이터를 반환하여 네트워크 부하를 줄여 성능을 향상시킨다. 특히 CDN과 같은 글로벌 캐시 서버를 사용하면 origin 서버(원본 서버)가 멀리 떨어져 있는 경우에도 네트워크 왕복 시간을 줄여 더 빠른 응답을 가능하게 한다.