HTTP | 섹션 8. HTTP 헤더2 - 캐시와 조건부 요청

728x90

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

 

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

실무에 꼭 필요한 HTTP 핵심 기능과 올바른 HTTP API 설계 방법을 학습합니다., [사진] 📣 확인해주세요!본 강의는 자바 스프링 완전 정복 시리즈의 세 번째 강의입니다. 우아한형제들 최연소 기술

www.inflearn.com

🟦 섹션 8. HTTP 헤더2 - 캐시와 조건부 요청

캐시란?

  • 클라이언트가 서버에 요청하는 자원은 단순 text부터 이미지, 영상, 파일까지 다양하다. 그 중에서는 용량이 커서 큰 네트워크 비용을 부담해야 하는 자원들이 있고, 변경 가능성이 잦지 않은 자원들이 있다.
  • 이런 자원들을 매 요청 시마다 새로 다운받는 것이 큰 비용 부담이므로 ‘캐시’를 활용한다.
  • 자원은 우선 ‘브라우저 캐시’에 저장해두고, 해당 자원이 변경되지 않았다면, 서버에서 다운받지 않고 ‘브라우저 캐시’에 저장해놓은 자원을 다시 사용한다는 개념이다.

⬛ 1. 캐시 기본 동작

◼️ 캐시가 없을 때

예를 들어 클라이언트가 GET/star.jpg 요청을 연속해서 두 번 했다고 가정해보자.

[첫 번째 요청] 시, 서버는 해당 요청에 맞는 응답을 http로 보낸다.

캐시 없을 때 1

[두 번째 요청] 시, 서버는 또 똑같이 해당 요청에 맞는 응답을 http로 보낸다.

캐시 없을 때 2

🟦 캐시 없는 상황 - 비효율적

캐시가 없는 상황에서는 위 그림처럼 똑같은 요청을 두 번 이상 요청해도, 똑같은 작업을 매번 해야 한다. → 비효율적이다 → 캐시 필요성

  • 데이터 변경 없어도 계속해서 네트워크를 통해 데이터를 다운로드 받아야 한다.
  • 인터넷 네트워크는 매우 느리고 비싸다
  • 브라우저 로딩 속도가 느리다.
  • 느린 사용자 경험

◼️ 캐시 적용

1) 캐시를 적용하면 첫 요청의 응답 결과를 웹 브라우저가 유효 시간 동안 내부의 브라우저 캐시 저장소에 저장해둔다.

캐시 적용 1

2) 이후 두 번째 요청에서는 우선 ‘브라우저 캐시 저장소’를 먼저 뒤진다.

  • 캐시 유효 시간 이내의 요청에 대해서 캐시저장소에 있는 데이터를 먼저 가져다 쓴다.

캐시 적용 2

🟦 캐시 적용 - 효율

  • 캐시 덕분에 캐시 유효 시간 동안은 같은 요청에 대한 자원을 위해 불필요하게 네트워크를 사용할 필요가 없어진다.
  • 비싼 네트워크 사용량을 줄일 수 있다.
  • 브라우저 로딩 속도가 매우 빠르다.
  • 빠른 사용자 경험

◼️ 캐시 유효 시간 초과 후의 요청 시, 다시 서버로부터 데이터를 조회하고 캐시 갱신한다.

캐시 시간 초과 시

  • 기존 캐시 저장소에 있던 데이터는 유효 시간이 지났으므로 다시 서버에 요청을 하고 해당 응답 결과를 다시 캐시에 저장해두고 유효 시간을 갱신시킨다.
  • 즉, 캐시 유효시간이 초과하면, 서버를 통해 데이터를 다시 조회하고 캐시를 갱신한다.
  • 이때 다시 네트워크 다운로드가 발생한다.

그런데, 유효 시간이 지났어도 변경점 없는 데이터를 다시 조회하기 위해 불필게 네트워크를 탈 필요가 있을까 ? 해결책이 있다!


⬛ 2. 검증 헤더와 조건부 요청 1

◼️ 캐시 시간 초과

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

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

2) 서버에서 기존 데이터를 변경하지 않음


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

캐시 만료 후에도 서버에서 데이터를 변경하지 않은 경우, 다시 서버로부터 데이터를 전송받는 대신에 저장해 두었던 캐시를 재사용 할 수 있다.

  • 단 , 클라이언트의 데이터와 서버 데이터가 ‘같다’는 사실 확인 방법 필요!

                                    → 그게 검증 헤더와 조건부 요청 이다.

     🟦 검증 헤더 추가 - 첫 번째 요청

데이터가 마지막에 수정된 시간 : Last Modified (검증 헤더)

응답 결과를 캐시에 저장하는데, 이때 데이터 최종 수정일 Last Modified를 함께 기록

      🟦 검증 헤더 추가 - 두 번째 요청

캐시가 가지고 있는 데이터 최종 수정일이 있다면 확인 후 서버에 함께 보냄

서버는 해당 데이터 최종 수정일을 (if-modified-since) 조건부 요청 확인해보니, 서버의 데이터 최종 수정일과 동일함을 확인 | 변경점 X

→ 수정 안되면 HTTP/1.1 304 Not Modified 보냄 - Http Body가 없음

→ 네트워크 부하가 확 줄어든다.

→ 304 Modified를 받았으면 캐시를 다시 재사용한다.


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

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

◼️ 검증 헤더

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

◼️ 조건부 요청 헤더

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

🟦 if-Modified-Since : 이후에 데이터가 수정되었다면 ?

◼️ 데이터 미변경 예시

  • 캐시 : 2020년 11월 10일 10:00:00 vs 서버 : 2020년 11월 10일 10:00:00
  • 시간 똑같음 → 304 Not Modified 헤더 데이터만 전송 (Body 미포함)
  • 전송 용량 0.1M (헤더 0.1M, 바디 1.0M)

◼️ 데이터 변경 예시

  • 캐시 : 2020년 11월 10일 10:00:00 vs 서버 : 2020년 11월 10일 11:00: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: “a2jioerj13”

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

ex) ETag : “aaaa” → ETag : “bbbb”

  • 진짜 단순하게 ETag만 보내서 같으면 유지, 다르면 다시 받기

◼️ ETag 활용한 경우

  • 시간이 초과되어도 캐시가 가지고 있는 ETag 확인한 뒤 수정된 건지 아닌지 확인하여 재사용 여부를 결정하면 된다.

◼️ ETag, If-None-Match 정리

  • 진짜 단순하게 ETag만 서버에 보내서 같으면 유지, 다르면 다시 받기
  • 캐시 제어 로직을 서버에서 완전히 관리
  • 클라이언트는 단순히 이 값을 서버에 제공하는 역할만

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

예) 애플리케이션 배포 주기에 맞춰서 ETag 모두 갱신!


⬛ 4. 프록시 캐시

◼️ Origin 서버 직접 접근

  • 예를 들어, 원 서버 (=Origin 서버)가 미국에 있다고 해보자.
  • 원본 리소스를 가지고 있는 origin 서버에 직접 접근하려고 한다면 시간이 매우 오래 걸릴 것이다.

◼️ 프록시 캐시 도입

  • Origin 서버에 직접 접근하는 시간을 줄이기 위해 ‘프록시 캐시 서버’를 도입한다.
  • 프록시 캐시 서버는 오리진 서버 대신 클라이언트 요청을 처리한다.
  • 첫번째, 두번쨰, 세번쨰 요청 등 … 모두 빠르게 응답받을 수 있게 된다.

설명

◼️ Cache-Control | 캐시 지시어 기타

  • Cache-Control : public

응답이 public 캐시에 저장되어도 된다.

  • Cache-Control : private

응답이 해당 사용자만을 위한 것임

private 캐시에 저장해야 함 (기본값)

  • Cache-Control : s-maxage

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

  • Age : 60 (HTTP 헤더)

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


⬛ 5. 캐시 무효화

◼️ Cache-Control | 확실한 캐시 무효화 응답

만약 확실하게 캐시를 무효화 하려면 아래를 담아서 응답해야 한다.

  • Cache-Control : no-cache, co-store , must-revalidate
  • Pragma: no-cache

HTTP 1.0 하위 호환

◼️ Cache-Control : no-cache

  • 데이터는 캐시해도 되지만, 항상 원 서버에 검증하고 사용해라(이름에 주의)

◼️ 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

  • no-cache의 경우, 항상 오리진 서버에서 검증해야 하므로 요청이 프록시 캐시 서버에서 오리진 서버로 전달된다.
  • 오리진 서버는 캐시를 검증하고 304 Not Modified 응답을 준다.
  • 이 응답을 받은 클라이언트는 캐시 데이터를 사용한다.
  • no-cache의 경우, 프록시 캐시 서버와 오리진 서버의 네트워크가 단절되어 오리진 서버에 요청을 보낼 수 없을 때 캐시 서버 설정에 따라 캐시 데이터 또는 에러를 응답한다.

◼️ must-revalidate

  • no-cache와 달리, must-revalidate의 경우, 프록시 캐시 서버와 오리진 서버의 네트워크가 단절되어 오리진 서버에 요청을 보낼 수 없을 때 항상 504 Gateway Timout 에러를 응답해야 한다.
728x90