검증 헤더와 조건부 요청 헤더
이전에 알아본 검증헤더와 조건부 요청 헤더를 정리하면 다음과 같다.
- 검증 헤더
- 캐시 데이터와 서버 데이터가 같은지 검증하는 데이터
- Last-Modified, ETag
- 조건부 요청 헤더
- 검증 헤더로 조건에 따른 분기
- If-Modified-Sine: Last-Modified 사용
- If-None-Match: ETag 사용
- 조건이 만족하면 200 OK, 만족하지 않으면 304 Not Modified로 응답
하지만 Last-Modified, If-Modified-Since에는 단점이 존재한다.
1초 미만(0.x초) 단위로 캐시 조정이 불가능 하고 날짜 기반의 로직을 사용하기 때문에 데이터를 수정해서 날짜가 다르지만, 같은 데이터를 수정해서 데이터 결과가 똑같은 경우(Ex.A > B > A로 원점 복귀 된 경우)나 서버에서 별도의 캐시 로직을 관리하고 싶은 경우(Ex.스페이스나 주석처럼 크게 영향이 없는 변경)에는 사용이 어렵다.
이럴 때 사용하는 것이 바로 ETag, If-None-Match 이다.
ETag와 If-None-Match
ETag란 Entity Tag의 줄임말로 쉽게 말하면 캐시용 데이터에 임의의 고유한 버전 이름을 달아주는 것이다.
Ex) ETag : "v1.0", ETag: "asd12sfda" ....
만약 데이터가 변경된 경우 이 ETag의 이름을 바꾸어서 변경한다. (Hash를 이용해서 자동 생성하는 것도 가능)
그렇다면 날짜가 아니라 ETag만 비교하여 같으면 유지, 다르면 다시 다운로드 받는 형태로 사용 가능한 것이다.
이렇게 사용하면 앞서 설명했듯 캐시로 할수 없는 소단위 변경이나 날짜 변동에 관계 없이 실제 변경 시에만 캐시를 변경하도록 할 수 있다.
보다 정확한 로직을 살펴보면 서버가 브라우저로 응답을 보낼때 ETag에 "aa"라는 값을 넣어서 보냈다고 생각해보자.
브라우저 캐시는 응답 결과를 캐시에 저장하며 ETag의 "aa"라는 값을 저장해 둘 것이다.
그 후, 캐시 시간이 초과되어 다시 브라우저가 요청을 보낼 때 If-None-Match라는 헤더에 현재 브라우저 캐시에 저장되어 있는 ETag의 "aa"라는 값을 보내는 것이다.
이렇게 하면 서버에서는 받은 태그 값을 비교하여 서버의 ETag와 동일한 경우 변경 사항이 없다고 판단하여 304 Not Modified를 전송하면서 Http Body를 뺀 헤더만 전송하여 캐시를 갱신하는 것이다.
또한 이렇게 하면 캐시 제어 로직을 서버에서 완전히 관리하고 클라이언트는 단순히 값을 서버에 제공만 하기 때문에 캐시 메커니즘을 숨길 수 있는 장점도 존재한다.
여러가지 헤더들
그럼 실제 캐시를 제어하는 헤더에 대해서 자세하게 살펴보자.
캐시 제어 헤더
- Cache-Control : 캐시 제어
- max-age
- 캐시 유효 시간, 초단위
- no-cache
- 데이터는 캐시해도 되지만, 항상 원(origin) 서버에 검증하고 사용
- 검증부 요청을 통하여 서버에 확인
- no-store
- 데이터에 민감한 정보가 있으므로 저장하면 안되는 경우
- 메모리에서 사용하고 최대한 빠르게 삭제
- max-age
- Pragma: 캐시 제어(하위 호환)
- no-cache
- HTTP 1.0 하위 호환
- no-cache
- Expires: 캐시 유효시간(하위 호환)
- 캐시 만료일을 정확한 날짜로 정적 지정 (초단위 까지)
- ex) expires: Mon, 01 Jan 1990 00:00:00 GMT
- HTTP 1.0부터 사용
- 현재는 더 유연한 Cache-Control: max-age 권장
- Cache-Control: max-age와 함께 사용하면 Expires는 무시 됨
- 캐시 만료일을 정확한 날짜로 정적 지정 (초단위 까지)
- 검증 헤더 (Validator)
- ETag
- Last-Modified
- 조건부 요청 헤더
- If-Match, If-None-Match
- ETag 값 사용
- If-Modified-Since, If-Unmodified-Sine
- Last-Modified 값 사용
- If-Match, If-None-Match