CS/HTTP

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

쿠릉쿠릉 쾅쾅 2022. 3. 4. 17:00
728x90

 

 

캐시 기본 동작

  • 웹 캐싱이란, 웹 서버 과부하에 의한 웹 트래픽을 감소시키고 사용자가 웹 검색을 할 때 대기시간을 줄이는 기술을 말한다.
  • 자주 찾는 웹 사이트나 파일을 따로 캐시(cache)에 저장해 놓고 필요할 경우 해당 사이트까지 직접 찾아가지 않고 임시 저장소에서 수시로 불러낼 수 있다.
  • 웹 캐싱은 인터넷 접속 속도를 줄이므로 인터넷 검색 속도를 향상 시킨다.
  • 캐싱은 주로 정적인 파일(static file)들을 불러오는데 사용된다.
    • 이미지 파일
    • CSS 파일
    • HTML 파일
    • 자바스크립트 파일

 

🔍 캐시 미적용

  • 데이터가 변경되지 않아도 계속 네트워크를 통해서 데이터를 다운 받아야 한다.
  • 인터넷 네트워크는 매우 느리고 비싸다. 그러므로 비효율적이다.
  • 브라우저 로딩 속도가 느려진다.

 

💡 첫 번째 요청

  • 클라이트가 서버에게 star.jpg 이미지 파일을 요청한다.
  • 서버는 해당 이미지가 있으면 응답을 해줘야하는데 이미지의 HTTP 헤더 + 바디를 합쳐서 대략 1.1M 용량의 데이터를 응답한다.
  • 클라이언트는 해당 이미지를 응답 받아 사용한다.

 

💡 두 번째 요청

  • 클라이언트는 또 다시 서버에게 star.jpg 이미지 파일을 요청한다.
  • 서버는 동일한 이미지를 또 1.1M 용량의 데이터를 응답한다.
  • 클라이언트는 해당 이미지를 응답 받아 사용한다.
  • 동일한 이미지를 요청하는데 네트워크를 통해 같은 데이터를 또 다운 받아야 한다.
  • 용량이 클 수록 비용이 커지고 브라우저 로딩속도가 느려진다.

 

🔍 캐시 적용

💡 첫 번째 요청

  • HTTP 응답 헤더에  cache-control  속성을 넣어서 캐시 유효시간을 넣어준다,
    •  cache-control:max-age=60   → 캐시 유효시간 : 60초
  • 그러면 캐시를 사용하기 때문에 응답 결과를 브라우저 캐시에 저장하며 60초간 유효하다.

       

💡 두 번째 요청 - 캐시 유효

  • 두 번째 요청할 때는 캐시를 먼저 조회한다.
  • 캐시가 존재하므로 해당 캐시에서 자료를 가져온다.
  • 캐시 덕분에 캐시 가능 시간동안 네트워크를 사용하지 않아도 된다.
  • 비싼 네트워크 사용량을 줄일 수 있다.
  • 브러우저 로딩 속도가 매우 빨라진다.

 

💡 세 번째 요청 - 캐시 시간 초과

  • 캐시 유효 시간이 초과하면, 서버를 통해 데이터를 다시 다운받아 캐시를 업데이트한다.
  • 이 때 다시 네트워크 다운로드가 발생한다.

 

 


 

 

검증 헤더와 조건부 요청 1

  • 캐시가 만료된 후에도 서버에서 데이터를 변경하지 않은 경우 서버에서 동일한 데이터를 요청해서 응답 받는 것은 비용 낭비다.
  • 이럴 때 저장해 둔 캐시를 재사용할 수 있도록 클라이언트의 데이터와 서버의 데이터가 동일하다는 것을 확인할 방법이 필요하다.
  • 그 방법이 검증 헤더와 조건부 요청이다.
  • 캐시 유효 시간이 초과해서 서버에 다시 요청하면 두 가지 상황이 존재한다.
    • 서버에서 기존 데이터를 변경한 경우 (노란색 별 이미지 →초록색 별 이미지)
    • 서버에서 기존 데이터를 변경하지 않은 경우 (노란색 별 이미지 유지)

 

🔍 검증 헤더 추가

💡 첫 번째 요청

  • 데이터가 마지막으로 수정된 시간 정보를 헤더에 작성한다.
    • 예) Last-Modified : 2020년 11월 10일 10:00:00
    • 실제 웹에서는 UTC 표기법으로 적혀있다.
  • 응답 결과를 캐시에 저장할 때 데이터 최종 수정일도 저장된다.

 

💡 두 번째 요청 - 캐시 시간 초과

  • 캐시가 만료되면 다시 요청을 해야하는데 캐시에 최종 수정일 정보(Last-Modified)가 담겨있다면 요청 헤더 중  if-modified-since  에 해당 날짜를 담아서 서버에 보낸다.

 

  • 응답 데이터에 HTTP Body가 없다.
  • 상태코드  304 Not Modified  는 기존 캐시 데이터와 변경되는 것이 없다는 것을 의미한다.

 

  • 해당 응답을 받은 클라이언트는 캐시를 갱신하고 다시 일정 시간 동안 유효하게 된다.

 

🧷 정리

  • 캐시 유효 시간이 초과해도, 서버의 데이터가 갱신되지 않으면 서버에서는 메시지 바디 없이  304 Not Modified  + 헤더 메타 정보로만 응답한다. 
  • 클라이언트는 서버가 보낸 응답 헤더 정보를 토대로 캐시 메타 정보를 갱신한다.
  • 클라이언트는 캐시에 저장되어 있는 데이터를 재활용한다.
  • 결과적으로 네트워크 다운로드가 발생하지만 용량이 적은 헤더 정보만 다운로드 받는다.

 

 


 

 

검증 헤더와 조건부 요청 2

  • 검증 헤더
    • 캐시 데이터와 서버 데이터가 같은지 검증하는 데이터다.
    • 검증 헤더 2가지
      •  Last-Modified 
      •  ETag  (Entity Tag)
  • 조건부 요청 헤더
    • 검증 헤더를 조건식으로 사용한 요청 헤더
      •  If-Modified-Since 
        • Last-Modified 사용한 것
      •  If-None-Match 
        • ETag 사용한 것
    • 조건이 만족하면  200 OK  상태코드로 응답한다. (브라우저 캐시 데이터와 서버 데이터 불일치)
    • 조건이 만족하지 않으면  304 Not Modified  상태코드로 응답한다. (브라우저 캐시 데이터와 서버 데이터 일치)

 

🔍 Last-Modified, If-Modified-Since 단점

  • 날짜 기반의 로직을 사용하므로, 데이터 수정 날짜를 기반으로만 데이터 일치/불일치를 판별한다. 
  • 만약에 서버에서 별도의 캐시 로직을 관리하고 싶을 경우 ETag를 사용할 것
    • 예) 데이터가 주석처럼 크게 영향이 없는 요소들을 수정하고 싶은데 캐시를 유지하고 싶은 경우

 

🔍 ETag (Entity Tag)

  • ETag HTTP 응답 헤더는 특정 버전의 리소스를 식별하는 식별자다.
  • 서버는 ETag를 HTTP 헤더에 담아 유효 토큰으로 통신한다.
    • 유효 토큰은 효율적인 자원 업데이트 체크를 가능하게 한다.
  • ETag는 캐시 데이터에 임의의 고유한 버전 이름이 존재한다.
    • 예) ETag : "v1.0"
  • 데이터가 변경되면 이름을 바꿔서 버전 명을 변경한다. (Hash를 다시 생성한다.)
    • 예) ETag : "aaa" → ETag : "bbb"
  • 클라이언트는 단순하게 ETag만 보내서 파일 버전이 서로 일치하면 캐시를 유지하고, 일치하지 않으면 서버한테 데이터를 다시 받는다.

 

💡 데이터 미 변경

  • 캐시 : 2020년 11월 10일 10:00:00 vs 서버 : 2020년 11월 10일 10:00:00
  • HTTP 응답 메시지에  304 NOT Modified  와 헤더 데이터만 전송한다. (메시지 바디 미포함)
  • 응답 데이터 전송 용량은 HTTP 헤더 용량이다.

 

💡 데이터 변경

  • 캐시 : 2020년 11월 10일 10:00:00 vs 서버 : 2022년 3월 1일 12:00:00
  • HTTP 응답 메시지에  200 OK  와 모든 데이터를 전송한다. (메시지 바디 포함)
  • 응답 데이터 전송 용량은 HTTP 메시지 전체 용량이다. (헤더 + 바디)

 

💡 ETag 동작 

✔ 첫 번째 요청

  • 서버는 클라이언트 요청에 응답할 때 헤더에 ETag를 작성해서 응답한다.

 

  • 브라우저 캐시에 ETag를 저장한다.

 

✔ 두 번쨰 요청 - 캐시 유효 시간 초과

  • 클라이언트는 캐시를 먼저 조회하고 유효한 캐시 데이터가 없으면 서버에게 요청을 보낸다.
  • 요청을 보낼 때 ETag 버전이 일치하는지 알아보기 위해 헤더에   If-None-Match  조건부 요청 넣는다.

 

  • 브라우저 캐시의 ETag 버전과 서버 Etag 버전이 일치하므로  304 Not Modified  상태코드를 응답 메시지로 보낸다.

 

  • 해당 응답을 받은 클라이언트는 만료된 기존 캐시를 갱신하여 재사용한다.

 

🧷 정리

  •  클라이언트에서 ETag만 서버에 보내서 같으면 캐시를 유지하고, 다르면 데이터를 다시 받는다.
  • 캐시 제어 로직을 서버에서 관리한다.
  • 클라이언트는 단순히 ETag 값만 서버에 제공하기 때문에 클라이언트는 캐시 매커니즘을 모른다.
    • 예) 애플리케이션 배포 주기에 맞춰 ETag를 모두 갱신한다.

 

 

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

  • 검증 헤더 (Validator)
    • ETag
      • 예) ETag : "v.10"
    • Last-Modified
      • 예) Last-Modified : Thu, 04 Jun 2020 07:19:24 GMT
  • 조건부 요청 헤더
    • ETag
      • If-Match
      • If-None-Match
    • Last-Modified
      • If-Modified-Since
      • If-Unmodified-Since

 

 

캐시와 조건부 요청 헤더

  • 캐시 제어 헤더
    • Cache-Control : 캐시 제어
    • Pragma : 캐시 제어 (하위호환)
    • Expires : 캐시 유효 기간 (하위호환)

 

🔍 Cache-Control

  • 캐시를 제어할 떄 쓰인다.
  • 캐시 지시어
    •  Cache-Control : max-age 
      • 캐시 유효 시간 설정 (초 단위)
    •  Cache-Control: no-cache 
      • 해당 데이터를 캐시해도 되지만, 항상 오리진(origin) 서버에 검증하고 사용한다.
    •  Cache-Control: no-store 
      • 데이터에 민감한 정보가 있으므로 저장하면 안된다.
      • 메모리에서 사용하고 최대한 빨리 삭제할 것. 

 

🔍 Pragma

  • 캐시 제어 헤더지만 잘 안쓰인다.

 

🔍 Expires

  • 캐시 만료일 지정 (초 단위가 아닌 날짜 단위)
    • 예) expires: Mon, 01 Jan 1990 00:00:00 GMT
  • 캐시 만료일을 정확히 날짜로 지정한다.
  •  Cache-Control: max-age  방법을 더 권장하므로 Expires는 잘 안쓰인다.
  •  Cache-Control: max-age  와 Expires가 함께 쓰이면 Expires는 무시된다.

 

 


 

 

프록시 캐시

  • 프록시 서버는 웹 사용자에 의해 빈번히 요청되는 데이터를 사용자와 지리적으로 가까운 웹캐시 서버에 보관해 빠른 서비스를 가능케 한다.
  • 그래서 웹 서버를 대신하여 HTTP 요구를 충족시켜준다.
  • 또한 저장 디스크를 가지고 있어 최근 호출된 객체의 사본을 저장한다.

 

🔍 프록시 캐시 도입 전

  • 프록시 캐시가 없으면 웹 브라우저가 미국에 있는 ORIGIN 서버에 직접 접근해야하기 때문에 접근 시간이 오래걸린다.

 

🔍 프록시 캐시 도입

  • 한국에 프록시 캐시서버를 두고 한국의 클라이언트는 프록시 캐시 서버를 통해 자료를 가져오도록 한다.
  • 여러 사람이 찾는 자료일수록 이미 캐시에 등록되어 있기 때문에 빠른 속도로 자료를 가져올 수 있다.
    • 같은 국내에 있기에 ORIGIN 서버에 접근하는 것보다 빠른 속도로 자료를 가져올 수 있다.
    • 예) 유튜브에서 고용량 영상을 빨리 볼 수 있는 이유다. 
  • 클라이언트에서 사용되고 저장되는 캐시를  private 캐시  라고 한다.
  • 캐시서버에 캐시를  public캐시  라고 한다.

 

🔍 Cache-Control

  • 캐시 지시어 기타
  •  Cache-Control : public 
    • 응답이 public 캐시에 저장되어도 된다는 것을 의미
  •  Cache-Control : private 
    • 응답이 해당 사용자만을 위한것임. private 캐시에만 저장한다. (기본값)
  • Cache-Control : s-maxage
    • 프록시 캐시에만 적용되는 max-age
    • 그냥 이런게 있다고 알고만 있으면 된다.
  • Age:60 (HTTP 헤더)
    • ORIGIN 서버에서 응답 후 프록시 캐시내에 머문 시간 (초)
    • 그냥 이런게 있다고 알고만 있으면 된다.

 

 


 

 

캐시 무효화

Cache-Control : no-cache, no-strore, must-revalidate
Pragma : no-cache
  • 캐시 무효화를 확실하게 해야하는 경우 이와 같이 적용하면 된다.
  • 캐시를 적용안해도 임의로 캐시로 적용되는 경우가 있다.
  • 특정 페이지에서 정말 캐시가 되면 안된다고 할 때 위 내용을 다 넣어주면 된다.
    • 예) 통장 잔고

 

🔍 Cache-Control

  •  Cache-Control : no-cache 
    • 데이터는 캐시해도 되지만, 항상 ORIGIN 서버에 검증하고 사용한다.
  •  Cache-Control : no-store 
    • 데이터에 민감한 정보가 있으므로 저장하면 안된다.
    • 메모리에 사용하고 최대한 빨리 삭제한다.
  •  Cache-Control : must-revalidate 
    • 캐시 만료 후 최초 조회시 ORIGIN 서버에 검증한다.
    • ORIGIN 서버 접근 실패시 반드시 오류가 발생해야 한다. - 504(Gateway Timeout)
    • must-revalidate는 캐시 유효 시간이라면 캐시를 사용한다.
  •  Pragma : no-cache 
    • HTTP 1.0 하위호환 버전일 때를 대비하여 캐시 무효화할 때 사용한다.

 

🔍 no-cache와 must-revalidate를 같이 써야 하는 이유

💡 no-cache 기본 동작

  • 캐시 서버 요청을 하면 프록시 캐시 서버에 도착하면 no-cache인 경우 ORIGIN 서버에 요청을 하게된다.
  • 그리고 ORIGIN 서버에서 검증 후 응답을 하게 된다.

 

  • 만약에 어떠한 이유라도 프록시 캐시 서버와 서버간 네트워크 연결이 단절되어 접근이 불가능하다면, no-cache에서는 응답이 오류가 아닌 오래된 데이터라도 보여주자는 개념으로 200 OK으로 응답을 한다.

 

💡 must-revalidate 기본 동작

  • 캐시 서버 요청을 해 프록시 캐시 서버로 갔을 때 캐시 서버와 ORIGIN 서버간의 연결이 단절되어 접근이 불가능하다면 must-revalidate에서는 ORIGIN 서버에 접근이 불가능할 경우 항상 오류가 발생해야 한다. (504-Gateway Timeout)

 

 

🧷 정리

  • 확실한 캐시 무효화 응답으로 작성한 헤더를 사용해야 한다면
  • 먼저 no-cache로 무조건 ORIGIN 서버에서 검증을 하게 한다.
  • 그리고 must-revalidate로 ORIGIN 서버의 검증이 안되면 오류가 발생하도록 한다.
  • 마지막으로 Pragma를 통해 혹시 모를 HTTP 1.0 이하의 버전의 하위호환도 적용하게 한다.

 

 

 

 

 

 


👀 참고자료

https://www.inflearn.com/course/http-%EC%9B%B9-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC/dashboard

 

모든 개발자를 위한 HTTP 웹 기본 지식 - 인프런 | 강의

실무에 꼭 필요한 HTTP 핵심 기능과 올바른 HTTP API 설계 방법을 학습합니다., - 강의 소개 | 인프런...

www.inflearn.com

 

 

https://www.youtube.com/watch?v=c33ojJ7kE7M 

 

https://drive.google.com/file/d/1RLv6bHT5QNc8fRf-8zQFrAYn7l6vLlvJ/view

 

캐시_20190717.pdf

 

drive.google.com

 

https://rinae.dev/posts/web-caching-explained-by-buying-milk-kr

 

[번역] 슈퍼마켓에서 우유를 사면서 웹 캐싱(Web Caching)을 알아봅시다

웹 개발을 할 때 기본 중의 기본이지만 대충 알고 넘어갔던 캐싱을 아주 깔끔하게 설명한 글

rinae.dev

 

728x90