본문 바로가기
JAVA & SPRING/HTTP 웹 기본 지식

HTTP 웹 기본 지식 7일차(HTTP 헤더 2 캐시와 조건부 요청)

by 눈오는1월 2023. 8. 28.
728x90

캐시가 없을 때 예전 요청과 같은 요청을 하게 되면 서버에서는 값이 변하지 않는 이상 똑같은 값으로 응답을 하게 된다.

이때 같은 파일을 보낼 때 헤더가 0.1 M 바디가 1.0M 크기일 경우에 총 1.1M 인 같은 것을 한번더 보내는 리소스가 발생한다.

이러한 상황을 해결하기 위한 것이 캐시이다.

캐시가 존재하면, 요청을 보낼때 서버에서 HTTP 헤더에 cashe-control에 캐시가 유요한 시간을 같이해서 전송한다. 이후 해당 데이터를 브라우저 캐시에 cashe-control에 적힌 시간만큼 저장한다.

브라우저에서는 해당 시간만큼 데이터를 브라우저 캐시에 저장하고 있다가 해당 시간 내 웹 브라우저가 필요할 경우 서버에 요청 없이 캐시에 저장되어 있던 데이터를 가져온다.

 

이때 만약 캐시 시간이 초과 됐을 경우 어떻게 될까?

캐시 유효 시간이 초과해 버리면 서버를 통해 다시 다운받고 캐시를 갱신한다 -> 이때 문제점이 만약 데이터가 변하지 않으면 불필요한 리소스가 또 발생한다.

이때 필요한 게 조건부 요청이 있다.

 

다시 웹 브라우저가 처음 유청할 때 서버에서는 cache-control과 함께 HTTP 헤더에 Last-Modified에 데이터가 마지막에 수정된 시간을 넣어서 보낸다.

이후에 웹 브라우저에서 캐시 유효 시간 초과 후 요청을 할 때 if-modified-since에 서버가 보냈던 last-modified값을 보내면 서버에서 데이터가 수정되지 않았으면 304 Not Modified라는 값과 함께 웹 브라우저로 전송한다. 이때 HTTP Body값은 존재하지 않는다.

(예시를 들 때 header는 0.1 M body는 1.0M 이므로  1.0M을 절약한 리소스 비용을 줄인 것이다.) 

이후 브라우저 캐시에 값이 갱신되고 브라우저는 캐시에 있는 값을 이용하게 된다.

 

이때 사용하는 검증 헤더와 조건부 요청에 대해 좀 더 알아보자.

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

검증 헤더

캐시 데이터와 서버 데이터가 같은지 검증하는 데 사용하는 데이터이다. 

종류로는 Last-Modified, ETag 가 존재한다.

 

조건부 헤더 요청

if-Modified-Since, if-None-Match 가 있고 첫 번째는 Last-Modified , 두 번째로는 ETag가 있다.

조건이 만족할 경우 200OK 그렇지 않으면 304 Not Modified를 발생시킨다.

 

앞서 언급한 Last-Modified, if-Modified-Since의 단점이 존재하고 이러한 단점을 해결한 게 ETag , if-None-Match가 있다.

 

Last-Modified, if-Modified-Since의 단점으로는

1초 미만의 단위로 캐시 조정이 불가능하고, 날짜 기반의 로직이 사용된다

만약 데이터가 A였는데 B였다가 다시 A로 바뀔 경우 데이터 값은 변하지 않았지만 이를 제대로 인지하지 못하고 변한 시간만 확인하므로 불 필요한 네트워크 리소스가 발생한다.

 

ETag, if-None-Match

ETag(Entity Tag)는 캐시에 임의의 고유한 이름을 붙인다. (해당 이름은 버전 이름을 붙이던가 혹은 해시 알고리즘을 통해 해시 결과로 붙일 수도 있다. -> 해시 알고리즘 사용 시 파일이 동일하다면 같은 결과를 받을 수 있다!)

ETag가 같은지 여부를 따져서 캐시를 갱신한다.

이러한 방식은 캐시 제어 로직을 서버에서 완전히 관리하고 위 Last-Modified를 사용한 단점을 해결할 수 있다.

 

캐시 제어 헤더

캐시 제어에 사용되는 헤더들이 있다.

  • Cache-Control
  • Pragma
  • Expires

이 3가지가 존재한다.

 

Cashe- Control: max-age

캐시 유효 시간, 초 단위의 값들이 저장되어있다

Cashe-Contorl : no-cache

데이터는 캐시해도 되지만 항상 원 서버에 검증하고 사용해야 한다.(원 서버 = origin 서버)

Cashe-Control: no-store

데이터에 민감한 정보가 있으므로 캐시에 저장하지 않고 메모리에 쓰고 빨리 삭제하라는 의미이다.

 

Pragma와 Expires는 

캐시 제어 하위 호환들이다.

Expires 같은 경우에는 캐시 만료일을 정확한 날짜로 지정하는 것인데 Cache-Control이 더 유연해서 이것을 권장하고 같이 사용되면 Expires는 무시된다.

 

프록시 캐시

만약 원서버가 미국에 있는 서비스를 한국에서 이용할 때 0.5초가 걸린다고 하자 해당 시간이 너무 오래 걸리므로 한국 어딘가에 미국 프록시 캐시 서버를 도입하면 웹 브라우저에서는 요청할때 프록시 캐시로 요청을 해서 값을 받을 수 있고 시간 소요가 더 적게 걸린다.

1번째 유저가 받을 때는 원서버에서 프록시 캐시 서버에 캐시값을 응답하므로 오래걸리지만 2번쨰 유저부터는 프록시 캐시 서버로 값을 바로 받을 수 있어서 시간이 빨리 단축됨

이렇게 프록시 캐시 서버에 저장되는 캐시를 public 캐시 웹 브라우저에 저장되는 캐시를 private 캐시라고 한다.

 

cache-control  나머지 헤더들

 

Cache-Control: public

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

Cache-Control: private

-응답이 해당 사용자만을 위한 것임, private 캐시에 저장해야 함(기본값)

Cache-Control: s-maxage

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

Age: 60 (HTTP 헤더)

-오리진 서버에서 응답 후 프록시 캐시 내에 머문 시간()

 

캐시 무효화

캐시 무효화라는 것도 존재하는데 말 그대로 캐시 사용을 무효화하는 것을 말한다

사용방법은

Cache-Control: no-cache, no-store, must-revalidate
Pragma: no-cache (HTTP 1.0 하위 호환)

이걸 다 적어주어야 가능하다

 

여기서 궁금한 점은 no-cache를 적는데 굳이 must-revalidate를 적어야 하냐고 생각이 들 수 있다.

만약 no-cache를 적었을 때 완벽하게 캐시무효화가 안될 수도 있는 이유는 웹 브라우저가 프록시 캐시를 요청했을때 프록시 캐시에서 원 서버로 순간 접속이 안되면 그냥 200 ok 응답을 보낼 수도 있다. 이러한 이유로 must-revalidate를 사용해서 이러한 점을 막을 수 있다.

no-cache 만 사용했을때
no-cache 와 must-revalidate를 같이 사용했을때

 

728x90