mojo's Blog

HTTP 헤더2 - 캐시와 조건부 요청 본문

HTTP

HTTP 헤더2 - 캐시와 조건부 요청

_mojo_ 2022. 7. 31. 23:01

※ 캐시 기본 동작

 

캐시가 없을 때 첫 번째 요청이 아래와 같이 수행된다고 가정해본다.

 

 

첫 번째 요청이 완료되면 두 번째 요청이 수행된다고 가정해본다.

 

 

위와 같이 데이터가 변경되지 않아도 계속 네트워크를 통해서 데이터를 다운로드 받아야 한다.

인터넷 네트워크는 매우 느리고 비싸며 브라우저 로딩 속도가 느리다.

 

이번엔 캐시를 적용하여 첫 번째 요청이 수행된다고 가정해본다.

 

 

첫 번째 요청이 완료되면 두 번째 요청이 수행된다고 가정해본다.

 

 

캐시를 적용함으로써 캐시 가능 시간동안 네트워크를 사용하지 않아도 된다.

비싼 네트워크 사용량을 줄일 수 있고 브라우저 로딩 속도가 매우 빠르다.

 

이번엔 캐시 시간이 초과된 상태에서 세 번째 요청이 수행된다고 가정해본다.

 

 

캐시 유효 시간이 초과하면, 서버를 통해 데이터를 다시 조회하고 캐시를 갱신한다.

이때 다시 네트워크 다운로드가 발생하게 된다.

동일한 데이터를 다시 요청하고 받는다는 것은 굉장히 비효율적이다.

이를 해결할 수 있는 방법이 있다고 하는데 계속해서 알아보도록 한다.

 

 

※ 검증 헤더와 조건부 요청1

 

캐시 유효 시간이 초과해서 서버에 다시 요청하면 다음 두 가지 상황이 나타난다.

1. 서버에서 기존 데이터를 변경함

2. 서버에서 기존 데이터를 변경하지 않음 (이 부분이 문제)

 

캐시 만료후에도 서버에서 데이터를 변경하지 않을 경우 다시 동일한 데이터를 요청할 때,

데이터를 전송하는 대신에 저장해 두었던 캐시를 재사용할 수 있다.

단, 클라이언트의 데이터와 서버의 데이터가 같다는 사실을 확인할 수 있는 방법이 필요하다.

 

 

검증 헤더를 추가할 경우 첫 번째 요청이 수행된다고 가정해본다.

 

 

첫 번째 요청이 완료되고 두 번째 요청이 수행된다고 가정해본다.

 

 

캐시에 있는 데이터 최종 수정일과 서버에서 데이터 최종 수정일이 동일하다는 것은 데이터가 아직 수정되지

않았다는 것을 의미한다.

그리고 if-modified-since 는 조건부 요청으로 서버에게 해당 시간에 데이터 수정이 일어났는지에 대해

확인할 수 있다.

 

 

따라서 서버에서는 HTTP 헤더와 바디를 같이 보내는 것이 아니라 HTTP 헤더만 전송한다.

그리고 캐시에서 응답 결과를 재사용하며 헤더 데이터에 대한 갱신이 이뤄진다.

 

★ 검증 헤더와 조건부 요청 정리

 

- 캐시 유효 시간이 초과해도 서버의 데이터가 갱신되지 않으면 304 Not Modified + 헤더 메타 정보만 응답

   (바디는 응답하지 않는 것이 핵심)

- 클라이언트는 서버가 보낸 응답 헤더 정보로 캐시의 메타 정보를 갱신

- 클라이언트는 캐시에 저장되어 있는 데이터를 재활용

- 결과적으로 네트워크 다운로드가 발생하지만 용량이 적은 헤더 정보만을 다운로드

 

직접 구글에서 입력하여 테스트를 해보도록 하자.

 

 

임의로 새로고침을 한번 하여 위 사진과 같이 띄웠고 Status 가 연한색은 캐시된 것, 검은색은 캐시되지

않은 것이다.

 

 

캐시된 것중 임의로 선택해본 결과 실제로 캐시가 되었음을 확인할 수 있다.

 

 

해당 png 를 더블클릭한 후에 새로고침을 할 경우 상태코드가 304 임을 알 수 있다.

즉, 재요청 결과가 수정되지 않았다는 것을 짐작할 수 있다.

 

 

※ 검증 헤더와 조건부 요청2

 

검증 헤더

 

  • 캐시 데이터와 서버 데이터가 같은지 검증하는 데이터
  • Last-Modified, ETag

조건부 요청 헤더

 

  • 검증 헤더로 조건에 따른 분기
  • If-Modified-Since: Last-Modified 사용
  • If-None-Match: ETag 사용
  • 조건이 만족하면 200 OK
  • 조건이 만족하지 않으면 304 Not Modified

 

예를 들어서 If-Modified-Since 에서 이후에 데이터가 수정된 경우를 고려해보자.

데이터 미변경 예시

 

  • 캐시: 2022년 07월 31일 02:00:00 vs 서버 : 2022년 07월 31일 02:00:00
  • 304 Not Modified, 헤더 데이터만 전송(BODY 미포함)
  • 전송 용량 0.1M (헤더 0.1M, 바디 1.0M)

데이터 변경 예시

 

  • 캐시: 2022년 07월 31일 02:00:00 vs 서버: 2022년 07월 31일 02:15:00
  • 200 OK, 모든 데이터 전송(BODY 포함)
  • 전송 용량 1.1M (헤더 0.1M, 바디 1.0M)

 

Last-Modified, If-Modified-Since 단점

 

- 1초 미만(0.x초) 단위로 캐시 조정이 불가능

- 날짜 기반의 로직을 사용

- 데이터를 수정해서 날짜가 다르지만, 같은 데이터를 수정해서 데이터 결과가 똑같은 경우

- 서버에서 별도의 캐시 로직을 관리하고 싶은 경우

   (ex : 스페이스, 주석처럼 크게 영향이 없는 변경에서 캐시를 유지하고 싶은 경우)

 

ETag, If-None-Match

 

- ETag(Entity Tag)

- 캐시용 데이터의 임의의 고유한 버전 이름을 달아둠

   (ex : ETag = "v1.0", ETag = "abcdjslek3bpd")

- 데이터가 변경되면 이 이름을 바꾸어서 변경함(Hash 를 다시 생성)

   (ex : ETag = "aaaaa" -> ETag = "bbbbb")

- 단순하게 ETag 만 보내서 같으면 유지하고 다르면 다시 받음

 

ETag 를 사용하여 첫 번째 요청이 수행된다고 가정해본다.

 

 

첫 번째 요청이 끝나면 두 번째 요청이 수행된다고 가정해본다.

 

 

캐시에 있는 데이터와 서버에 있는 데이터가 ETag 를 통해 수정되지 않았음을 알 수 있다.

 

 

 

따라서 HTTP Body 를 제외한 헤더만 받게 되며 헤더 데이터를 갱신하게 된다.

동시에 캐시에서 조회를 할 수 있게 된다.

 

ETag, If-None-Match 정리

 

- 단순하게 ETag 만 서버에 보내서 같으면 유지, 다르면 다시 받기

- 캐시 제어 로직을 서버에서 완전히 관리함

- 클라이언트는 단순히 이 값을 서버에 제공 (클라이언트는 캐시 매커니즘을 모름)

   (ex : 서버는 배타 오픈 기간인 3일 동안 파일이 변경되어도 ETag 를 동일하게 유지)

   (ex : 애플리케이션 배포 주기에 맞추어 ETag 모두 갱신)

 

 

※ 캐시와 조건부 요청 헤더

 

★ Cache-Control

캐시 지시어(directives)

 

Cache-Control : max-age

- 캐시 유효 시간, 초 단위 (보통 길게 잡는다고 한다)

Cache-Control : no-cache

- 데이터는 캐시해도 되지만, 항상 origin 서버에 검증하고 사용 (proxy 캐시에서 검증 x)

Cache-Control : no-store

- 데이터에 민감한 정보가 있으므로 저장하면 안됨 (메모리에서 사용하고 바로 삭제)

 

Expires

캐시 만료일 지정(하위 호환)

 

expires : Mon, 01 Jan 1990 00:00:00 GMT

- 캐시 만료일을 정확한 날짜로 지정

- HTTP 1.0 부터 사용

- 지금은 더 유연한 Cache-Control : max-age 를 권장

- Cache-Control : max-age 와 함께 사용 하면 Expires 는 무시

 

검증 헤더와 조건부 요청 헤더

 

검증 헤더 (Validator)

- ETag : "v1.0", ETag : "asdfo4329alg"

- Last-Modified : Thu, 04 Jun 2022 01:36:00 GMT

 

조건부 요청 헤더 

- If-Match, If-None-Match : ETag 값 사용

- If-Modified-Since, If-Unmodified-Since : Last-Modified 값 사용

 

 

※ 프록시 캐시

 

위에서 Cache-Control : no-cache 에서 언급한 origin 서버에 대해 이해할 필요가 있다.

다음 사진을 통해 origin 서버를 알아보도록 한다.

 

 

미국 어딘가에 있는 origin 서버로부터 어떤 이미지를 다운받는데 500ms 가 걸린다고 가정하였다.

한국으로부터 미국까지 데이터를 가져오는데 걸리는 시간은 많이 걸리는 것이 정상적이다.

따라서 이를 해결하기 위해 한국 어딘가에 프록시 캐시를 도입한다.

 

 

★ Cache-Control

캐시 지시어(directives) - 기타

 

Cache-Control : public

- 응답이 public 캐시에 저장되어도 됨

Cache-Control : private

- 응답이 해당 사용자만을 위한 것이며, private 캐시에 저자애야 함(default 값)

Cache-Control : s-maxage

- 프록시 캐시에만 적용되는 max-age

Age : 60 (HTTP 헤더)

- origin 서버에서 응답 후 프록시 캐시 내에 머문 시간(초)

 

 

※ Cache-Control

 

Cache-Control : no-cache, no-store, must-revalidate

Pragma : no-cache (HTTP 1.0 하위 호환)

 

Cache-Control : no-cache

- 데이터는 캐시해도 되지만, 항상 origin 서버에 검증하고 사용

Cache-Control : no-store

- 데이터에 민감한 정보가 있으므로 저장하면 안됨 (메모리에서 사용하고 바로 삭제)

Cache-Control : must-revalidate

- 캐시 만료후 최초 조회시 원 서버에 검증해야 함

- 원 서버 접근 실패시 반드시 오류가 발생해야 함 (504 - Gateway Timeout)

- must-revalidate 는 캐시 유효 시간이라면 캐시를 사용함

Pragma : no-cache

- HTTP 1.0 하위 호환

 

no-cache vs must-revalidate

no-cache 기본 동작

 

프록시 캐시 서버와 원 서버의 네트워크가 활성화 되어있을 때 다음과 같다.

 

 

이번엔 프록시 캐시 서버와 원 서버의 순간 네트워크가 단절이 되어 접근이 불가능한 경우이다.

 

 

접근이 불가능한 경우 캐시 서버 설정에 따라서 캐시 데이터를 반환할 수 있다.

보통 오류 보다는 오래된 데이터를 보여주는 방식으로 응답을 200 OK 으로 보낸다고 한다.

 

이번엔 must-revalidate 에 대한 상황으로 다음과 같다.

 

 

돈과 관련된 정보는 이전 정보를 보여준다면 문제가 있다.

따라서 이러한 경우에는 must-revalidate 를 통해서 에러를 반환하는 것이 적합하다.

 

'HTTP' 카테고리의 다른 글

HTTP 헤더1 - 일반 헤더  (0) 2022.01.26
HTTP 상태코드  (0) 2022.01.24
HTTP 메서드 및 활용  (0) 2022.01.23
HTTP 기본  (0) 2022.01.20
URI와 웹 브라우저 요청 흐름  (0) 2022.01.19
Comments