이번 포스팅에서는 일반 헤더를 정리했던 이전 포스팅에 이어서 캐시와 조건부 요청 관련 헤더들에 대해 다루어보려고 한다.
캐시와 조건부 요청에 관련된 헤더들을 살펴보기 앞서, 캐시의 기본 동작에 대해 간단히 알아보고 넘어가자.
1. 첫 번째 요청
클라이언트가 서버에게 jpg
파일에 대해 요청
서버는 Body
에 파일을 담아 클라이언트로 전송
이 때, Header
와 Body
포함 메시지 크기는 1.1 M 로 가정
2. 두 번째 요청
클라이언트가 서버에게 이전과 동일한 jpg
파일에 대해 요청
서버는 Body
에 파일을 담아 클라이언트로 전송
이 때, Header
와 Body
포함 메시지 크기는 1.1 M 로 첫 번째 요청과 동일
데이터가 변경되지 않아도 계속 네트워크를 통해서 데이터를 다운로드 받아야 한다.
브라우저 로딩 속도가 느리다.
1. 첫 번째 요청
클라이언트가 서버에게 jpg
파일에 대해 요청
서버는 Body
에 파일을 담아 클라이언트로 전송
이 때, Header 와 Body 포함 메시지 크기는 1.1 M 로 가정
2. 두 번째 요청
jpg
파일을 캐시에서 참조동일한 데이터를 캐시에 저장해두고 이를 참조하여 불필요한 네트워크 다운로드 효과적 감소
브라우저 로딩 속도가 빠름
이렇게, 캐시를 사용하게 되면 서버로부터 불필요한 네트워크 다운로드를 효과적으로 줄일 수 있다.
한 번 응답받았던 데이터는 브라우저의 캐시 저장소에 남아 일정 시간 내에 계속해서 참조할 수 있기 때문이다.
이는 결과적으로 네트워크 다운로드 용량을 줄이는 것 뿐 아니라, 브라우저의 로딩 속도를 개선해 더 빠른 사용자 경험이 가능하도록 한다.
이제 캐시와 조건부 요청 관련 헤더들을 본격적으로 알아보자.
📌 Cache
- Cache-Control
- Pragma
- Expires
Cache-Control
캐시의 유효 시간을 명시하는 헤더로, 유효 시간이 초과되면 캐시 데이터를 사용할 수 없기 때문에 원칙적으로 다시 네트워크 다운로드를 통해 데이터를 받아와야 한다.
캐시의 유효 시간
Parameters
ex) cache-control: max-age=60
. . .
Pragma
현재는 HTTP 1.0 하위 호환을 위해 사용하는 캐시 제어 헤더이다. Cache-Control 과 동일한 역할을 수행하지만 권장되지 않는다.
ex) pragma: no-cache
. . .
Expires
캐시의 만료일을 명시하는 헤더로, 정확한 날짜를 지정하여야 한다.
유효 시간을 명시하는 Cache-Control 과 비교하여 유연하지 않다는 단점이 있어 권장되지 않고, 현재는 하위 호환을 위해 사용되는 캐시 제어 헤더이다.
ex) expires: Wed, 21 Oct 2015 07:28:00 GMT
. . .
📌 Validation
- Last-Modified
- ETag
Last-Modified
검증 헤더 중 Last-Modified 는 데이터의 최종 수정 시각을 명시한다. 클라이언트가 캐시 유효 기간이 초과된 데이터를 서버에 요청하는 경우, 이를 기준으로 데이터가 수정되었는지 검증할 수 있다.
즉, 서버의 데이터 최종 수정 시각이 Last-Modified 보다 이후라면, 데이터가 수정된 것으로 간주하고, 서버의 데이터 최종 수정 시각이 Last-Modified 와 같다면, 데이터가 수정되지 않은 것으로 간주한다.
If-Modified-Since 와 함께 사용된다.
데이터가 마지막에 수정된 시간
ex) last-modified: Tue, 15 Mar 2022 06:48:06 GMT
. . .
ETag
하지만, Last-Modified 는 단순히 최종 수정 시각을 기준으로 데이터의 변경 및 수정을 검증하기 때문에 A -> B -> A 와 같은 동일 데이터로의 변경은 검증해내지 못한다는 한계점이 있다.
따라서 검증 헤더 중 ETag 를 사용하면, 서버에서 별도의 캐시 로직을 관리할 수 있으며, 해시값을 활용해 콘텐츠를 기반으로 정확하게 검증할 수도 있다.
데이터가 변경되면 ETag 가 변경되기 때문에, 단순히 ETag 가 같으면 데이터가 수정되지 않은 것이고, ETag 가 다르면 데이터가 수정된 것으로 간주하게 된다.
If-None-Match 와 함께 사용된다.
데이터의 고유 식별값
ex) ETag: "a2jiodwjekjl3"
, ETag: "v1.0"
. . .
📌 Conditional Requests
- If-Modified-Since
- If-Unmodified-Since
- If-None-Match
- If-Match
If-Modified-Since
조건부 요청 헤더 중 If-Modified-Since 는 클라이언트의 요청 시 사용되며, 서버의 데이터 최종 수정 시각과 캐시 데이터의 Last-Modified 를 비교하여 데이터 수정 여부를 확인하기 위해 사용한다.
이 때, 데이터가 수정되지 않았다면 이전 캐시를 재사용하게 되고, 데이터가 수정되었다면 새로운 데이터를 Body
에 담아 전송받게 된다.
데이터가 Last-Modified 이후로 수정되었는지 확인
304 Not Modified
응답 ---> 캐시 재사용200 OK
응답 ---> Body 에 새로운 데이터 전송 (네트워크 다운로드)단, 304 Not Modified
응답 메시지에 Body
사용 불가
If-None-Match
조건부 요청 헤더 중 If-None-Match 는 클라이언트의 요청 시 사용되며, 서버의 데이터 ETag 와 캐시 데이터의 ETag 를 비교하여 데이터 수정 여부를 확인하기 위해 사용한다.
이 때, 데이터가 수정되지 않았다면 이전 캐시를 재사용하게 되고, 데이터가 수정되었다면 새로운 데이터를 Body
에 담아 전송받게 된다.
데이터의 ETag 를 기준으로 수정되었는지 확인
304 Not Modified
응답 ---> 캐시 재사용200 OK
응답 ---> Body 에 새로운 데이터 전송 (네트워크 다운로드)단, 304 Not Modified
응답 메시지에 Body
사용 불가
If-Unmodified-Since 와 If-Match 는 각각 If-Modified-Since, If-None-Match 와 반대의 역할을 수행한다.
하지만 Last-Modified 와 ETag 를 기준으로 데이터의 수정 여부를 확인하는 헤더인 것은 동일하다.
만약, 캐시를 사용해선 안되는 페이지가 존재한다면, 다음과 같이 Setup 하여야 한다.
Cache-Control: no-cache, no-store, must-revalidate
Pragma: no-cache
이 때, must-revalidate
가 사용되는 이유는 no-cache
에 의해 Origin Server 에 검증 요청을 보내는 도중 Origin Server 와 Proxy Cache Server 의 연결이 끊어져 검증이 불가능할 경우, 504 Gateway Timeout
오류를 발생시키기 위해서이다.
몇몇 Proxy Cache Server 에서는 Origin Server 에 접근이 불가능해질 경우에 검증을 거치지 않고 이전의 캐시 데이터를 반환하기 때문이다.
특히, 통장 잔고와 같은 중요 데이터의 경우, Origin Server 와의 연결이 불가능하다고 해서 변경 전의 데이터를 반환할 수는 없으므로 must-revalidate
를 활용해 오류를 발생시키기도 한다.
따라서, 캐시를 사용해서는 안되는 페이지의 경우에도 must-revalidate
를 명시하여 Proxy Cache Server 가 자체적으로 캐시 데이터를 반환하는 케이스를 사전에 차단하여야 한다.
추가적으로, Pragma: no-cache
의 경우에는 과거 HTTP 1.0 버전의 호환을 고려하였다고 볼 수 있다.
이렇게 캐시와 조건부 요청 관련 헤더들을 정리하면서 마지막 HTTP 시리즈 포스팅을 마치게 되었다.