효율적인 캐싱을 위한 조건부 요청에 대해서 알아본다.
Last-Modified (데이터가 마지막에 수정된 시간)을 이용
요청
GET /car.jpg
응답
HTTP/1.1 200 OK
Content-Type: image/jpeg
Content-Length: 40000
cache-control: max-age=60
Last-Modified: 2021-06-25 10:00:00
eyJzdWIiOiJzYWxseUBpbWFzbGFiLmN...
첫 번째 요청에서 클라이언트는 응답 결과, 캐시 유효 시간, 마지막 수정 일시를 저장한다.
61초 후에 재요청
GET /car.jpg
if-modified-since: 2021-06-25 10:00:00
이때, 로컬에 저장되어 있는 클라이언트의 캐시 유효 시간은 60초이므로 서버에 마지막 수정 일시를 전달한다.
서버는 클라이언트에서 전달한 마지막 수정일시와 요청 리소스에 대한 마지막 수정일시를 비교한다.
이때 수정된 경우와 수정되지 않은 경우 두 경우가 있다.
응답 (리소스의 마지막 수정 일시가 클라이언트에서 전달한 마지막 수정일시를 초과하지 않는 경우)
HTTP/1.1 304 Not Modified
Content-Type: image/jpeg
Content-Length: 40000
cache-control: max-age=60
Last-Modified: 2021-06-25 10:00:00
응답 (리소스의 마지막 수정 일시가 클라이언트에서 잔달한 마지막 수정일시를 초과한 경우)
HTTP/1.1 200 OK
Content-Type: image/jpeg
Content-Length: 40000
cache-control: max-age=60
Last-Modified: 2021-06-25 11:00:00
eyJzdWIiOiJzYWxseUBpbWFzbGFiLmN...
정리를 해보면
- 캐시 유효 시간이 초과하더라도 서버의 데이터가 수정되지 않으면 304 Not Modified 응답으로 바디에 들어가는 데이터의 양을 절약할 수 있다.
- 클라이언트는 서버가 보낸 응답 헤더 정보로 캐시의 메타 정보를 갱신할 수 있다.
Last-Modified와 if-modified-since 를 통한 효율적인 캐싱에 대해서 알아보았다.
아래에서는 ETag와 If-None-Match 를 사용한 조금 더 효율적인 캐싱에 대해서 알아본다.
ETag (Entity Tag)
- 캐시용 데이터에 임의의 고유한 버전 이름을 달아둔다.
- 예) ETag: "v1.0", ETag: "rand1111"
- 데이터가 변경되면 고유한 버전 이름을 바꾸어서 다시 변경한다.(Hash를 다시 생성)
- 예 ETag: "rand1111" -> "rand2222"
- 데이터가 변경되면 데이터를 기반으로 생성한 해시값이 변경된다. 이러한 해시의 특징을 이용한 방식이다.
ETag와 If-None-Match를 사용한 요청과 응답의 흐름을 살펴본다.
1) 요청
GET /car.jpg
2) 응답
HTTP/1.1 200 OK
Content-Type: image/jpeg
Content-Length: 40000
cache-control:max-age=60
ETag: "rand1111"
eyJzdWIiOiJzYWxseUBpbWFzbGFiLmN...
# 브라우저의 캐시 시간을 초과하지 않은 경우 서버로 요청을 보내지 않는다. 아래는 캐시 시간을 초과 하였다고 가정한다.
3) 요청
GET /car.jpg
If-None-Match: "rand1111"
4) 응답 (서버의 데이터가 변경되지 않았다고 가정)
HTTP/1.1 304 Not Modified
Content-Type: image/jpeg
Content-Length: 40000
cache-control: max-age=60
ETag: "rand1111"
4)의 응답 메시지의 바디를 살펴보면 데이터가 없는 것을 확인할 수 있다.
캐시 제어 헤더
Cache-Control: 캐시 제어
- Cache-Control: max-age (캐시 유효 시간, 초 단위)
- Cache-Control: no-cache (캐시가 가능하지만 항상 ORIGIN 서버에 검증하고 사용해야한다.)
- Cache-Control: no-store (데이터에 민감한 정보가 있으므로 저장하면 안된다.)
- Cache-Control: public (응답이 public 캐시에 저장 가능하다.)
- Cache-Control: private (응답이 해당 사용자만을 위한 것이므로 private 캐시에 저장해야한다.)
- Cache-Control: s-maxage (프록시 캐시에만 적용되는 max-age)
- Age: 60 (ORIGIN 서버에서 응답 후 프록시 캐시 내에 머문 시간을 나타낸다.)
Pragma: 캐시 제어
Expires: 캐시 유효 기간
캐시 무효화
Cache-Control: no-cache, no-store, must-revalidate
- Cache-Control: no-cache
- 데이터는 캐시해도 되지만, 항상 ORIGIN 서버에 검증하고 사용해야한다.
- Cache-Control: no-store
- 데이터에 민감한 정보가 있으므로 저장하면 안된다.
- Cache-Control: must-revalidate
- 캐시 만료후 최초 조회시 ORIGIN 서버에 검증해야한다.
- ORIGIN 서버 접근 실패시 반드시 504(Gateway Timeout) 오류가 발생해야한다.
- 캐시 유효 시간이라면 캐시를 사용해야한다.
must-revalidate를 사용하지 않은 상태에서 프록시 캐시에 데이터가 캐싱되어 있다고 가정해보자.
만약 ORIGIN 서버에 문제가 생겨서 통신이 불가능한 상황이 되더라도 프록시 캐시는 클라이언트에게 200 OK 와 함께 캐싱된 데이터를 전달할 것이다.
절대로 캐싱되지 말아야하는 상황이라면 위의 캐시 지시어를 사용하여 캐싱을 방지하도록 하자.
'Infrastructure > Network' 카테고리의 다른 글
[HTTP] 헤더 - 3 (일반 정보) (0) | 2021.06.28 |
---|---|
[HTTP] 헤더 - 2 (전송 방식) (0) | 2021.06.28 |
[HTTP] 헤더 - 5 (캐시) (0) | 2021.06.25 |
[HTTP] 헤더 - 1 (일반 헤더) (0) | 2021.06.25 |
[HTTP] 상태 코드 (3xx) (0) | 2021.06.25 |