관리 메뉴

나구리의 개발공부기록

HTTP 헤더2 - 캐시와 조건부 요청, 캐시 기본 동작, 검증 헤더와 조건부 요청, 캐시와 조건부 요청 헤더, 프록시 캐시, 캐시 무효화 본문

인프런 - 스프링 완전정복 코스 로드맵/모든 개발자를 위한 HTTP 웹 기본 지식

HTTP 헤더2 - 캐시와 조건부 요청, 캐시 기본 동작, 검증 헤더와 조건부 요청, 캐시와 조건부 요청 헤더, 프록시 캐시, 캐시 무효화

소소한나구리 2024. 2. 6. 12:46

  출처 : 인프런 - 모든 개발자를 위한 HTTP 웹 기본 지식(유료) / 김영한님

  유료 강의이므로 정리에 초점을 두고 코드는 일부만 인용  

https://inf.run/8ZEU8


1. 캐시 기본 동작

1) 기본 동작 설명

(1) 캐시가 없을 때

  • 데이터가 변경되지 않아도(같은 요청을 여러번) 계속 네트워크를 통해서 데이터를 다운로드 받아야함
  • 인터넷 네트워크는 PC의 메모리나 하드디스크에 비에 상대적으로 매우 느리고 비쌈
  • 사용자 입장에서는 브라우저 로딩속도가 느려짐(느린 사용자 경험)

 

(2) 캐시 적용

  • cache-control(캐시 유효시간) 이라는 메시지를 HTTP헤더에 넣을 수 있음
  • 최초요청시 서버에서 받은 응답 결과를 캐시에 저장하고 같은 요청이 오게 되면 브라우저 캐시에서 조회하여 결과를 응답
  • 캐시 덕분에 캐시 유효시간동안 네트워크를 사용하지 않아도 됨
  • 비싼 네트워크 사용량을 줄일 수 있고 브라우저 로딩 속도가 매우 빠름(빠른 사용자 경험)
  • 예) 웹 브라우저 들어갔던곳을 다시 재접속 했을 때 굉장히 빨리 열림

 

(3) 유효 시간이 초과

  • 캐시 유효시간이 초과하면 브라우저 캐시에 동일한 데이터가 있음에도 서버를 통해 데이터를 다시 조회하고 캐시를 갱신하고 다시 네트워크 다운로드가 발생 됨

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

1) 캐시 시간 초과

(1) 캐시 유효 시간이 초과해서 서버에 다시 요청하면 두가지 상황이 나타남

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

(2) 서버에서 기본 데이터를 변경하지 않았을 경우

  • 캐시 만료 후에도 서버에서 데이터를 변경하지 않았을 경우 데이터를 전송하는 대신 저장해 두었던 캐시를 재사용 할 수 있음
  • 단, 클라이언트의 데이터와 서버의 데이터가 같다는 사실을 확인할 수 있는 방법이 필요함 - 검증 헤더 추가로 해결

2) 검증 헤더 추가

(1) 첫 번째 요청

  • Last-Modified(마지막으로 수정된 시간)를 추가해서 서버에 요청 (시간은 UTC 표기법으로 작성)
  • 서버에서는 응답 데이터에 요청한 데이터의 최종 수정일 정보를 함께 포함하여 웹 브라우저에 전송하고 웹 브라우저는 응답 결과를 캐시에 저장

 

(2) 두 번째 요청 - 유효기간 초과

  • 캐시 유효 시간이 지난 후 클라이언트에서 동일한 요청이 한번 더 올 경우 브라우저에 저장된 데이터의 최종 수정일 정보를 서버에 전송
  • 서버에서는 웹브라우저가 요청한 데이터를 최종 수정일로 비교하여 데이터가 동일한지(수정이 안되었는지) 검증을 하고 데이터가 같으면 304 Not Modified 상태코드와 함께 HTTP Body가 없는 응답 메시지를 웹 브라우저에 전송
  • 실제 데이터(HTTP body)는 없이 헤더의 정보만 웹 브라우저에 전송되므로 용량이 크게 줄어들어 네트워크 부하가 감소됨
  • 브라우저캐시가 응답메시지를 받아 동일한 데이터임을 확인하여 캐시를 다시 세팅(캐시유효기간)
  • 브라우저에서 요청한 데이터를 캐시가 조회하여 전송

 

(3) 정리

  • 캐시 유효 기간이 초과해도 서버의 데이터가 갱신되지 않으면 304 Not Modified 상태코드와 헤더 메타 정보만 응답함
  • 클라이언트는 서버가 보낸 응답 헤더 정보로 캐시의 메타 정보를 갱신하고 캐시에 저장되어있는 데이터를 재활용
  • 결과적으로 네트워크 다운로드가 발생하지만 용량이 매우 적은 헤더 정보만 다운로드하기때문에 매우 실용적으로 문제가 해결 됨

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

(1) 검증헤더

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

(2) 조건부 요청 헤더

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

4) If-Modified-Since 이후 데이터 변경/미변경 예시

(1) 데이터 미변경

  • 캐시에 저장된 데이터와 서버의 저장된 데이터가 마지막 수정날짜까지 동일
  • 304 Not Modified 상태코드와 헤더 데이터만 전송(Body 미포함)
  • 전송 용량이 크게 줄어듦

(2) 데이터 변경

  • 캐시 : ... 10일 10:00:00 vs .... 10일 11:00:00  / 차이발생
  • 200 OK 모든 데이터 전송(Body 포함)
  • 최초에 요청된 데이터의 용량이 전송 됨

(3) Last-Modified, If-Modified-Since 단점

  • 1초 미만(0.x초) 단위로 캐시 조정이 불가능
  • 날짜 기반의 로직 사용하기 때문에 데이터를 수정해서 날짜가 달라졌지만 최종 데이터의 수정 결과가 원본의 데이터와 같은 경우에도 전체 데이터를 다시 전송함 (복사-붙여넣기, 수정 후 원복 등)
  • 서버에서 별도의 캐시 로직을 관리하고 싶은 경우 방법이 없음

5) ETag, If-None-Match

(1) ETag: Entity Tag

  • 캐시용 데이터에 임의의 고유한 버전 이름을 달아둠(버전으로 표시, 임의값 지정, Hash라이브러리를 통해서 Hash값을 지정 등)
  • 데이터가 변경되면 임의의 고유한 값(ETag) 이름을 바꾸어서 저장
  • Hash값을 ETag로 지정하는 경우 파일이 완전히 동일하면 같은 Hash값을 주기 때문에 이런경우 캐시가 그대로 적용 될 수 있음
  • 클라이언트 입장에서 ETag만 보내서 같으면 유지, 다르면 다시 데이터를 받아서 저장

(2) 첫 번째 요청

  • 최초 데이터 요청시 서버에서 데이터에 ETag를 생성해서 응답
  • 캐시는 응답 결과를 캐시에 저장

 

(3) 두 번째 요청

  • 캐시 유효 기간이 지난 후에 웹 브라우저에서 다시 동일한 요청을 하면 캐시에 저장된 ETag 값을 꺼내서 'If-None-Match: ETag값' 으로 서버에 전송(ETag값과 매치된 값이 없으면 새로운 데이터를 보내라!)
  • 서버에서는 받은 ETag값과 동일한 ETag값을 가진 데이터를 찾아 데이터가 수정되었는지 검증
  • 서버에서 찾은 ETag값과 요청온 ETag값이 일치하면 요청이 실패하여 304 Not Modified 상태 코드를 헤더에 반영하고 클라이언트에 전송(HTTP Body는 미포함)
  • 브라우저 캐시는 응답 받은 헤더 데이터만 갱신하고(유효시간 재설정) 기존 데이터는 유지
  • 웹브라우저에서 요청한 데이터를 캐시에서 조회하여 응답

 

(4) 정리

  • 단순히 ETag만 서버에 보내서 같으면 유지하고 다르면 다시 받는 메커니즘
  • 캐시 제어 로직을 서버에서 완전히 관리하고 클라이언트는 단순히 이 값을 서버에 제공(클라이언트는 캐시 메커니즘을 모름)
  • 예) 애플리케이션 배포 주기에 맞추어서 ETag를 모두 갱신

3. 캐시와 조건부 요청 헤더

1) 캐시 제어 헤더

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

(1) Cache-Control: 캐시 지시어 (Directives)

  • Cache-Control: max-age : 캐시 유효 시간, 초 단위
  • Cache-Control: no-cache: 데이터는 캐시해도 되지만 중간 캐시 서버가 아닌 항상 원 서버(origin서버)에 데이터를 검증하고 사용
  • Cache-Control: no-store: 데이터에 민감한 정보가 있으므로 저장하면 안됨(메모리에서 사용하고 최대한 빨리 삭제)

(2) Pragma(캐시 제어)

  • Pragma: no-cache
  • HTTP 1.0 하위호환으로 지금은 거의 사용하지 않음

(3) Expires(캐시 만료일 지정)

  • expires: Mon, 01 Jan 1990 00:00:00 GMT
  • 캐시 만료일을 정확한 날짜로 지정
  • HTTP 1.0 부터 사용했지만 지금은 더 유연한 Cache-Control: max-age를 사용함(권장)
  • Cache-Control: max-age와 함께 사용되면 Expires는 무시됨

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

(1) 검증 헤더(Validator)

  • ETag: "V1.0", ETag: "asldf238" 등등
  • Last-Modified : Thu, 02 Jan 2020 00:00:00 GMT

(2) 조건부 요청 헤더

  • If-Match, If-None-Match: ETag 값 사용
  • If-Modified-Since, If-Unmodified-Since: Last-Modified 값 사용

4. 프록시 캐시

(1) 원 서버(진짜서버, origin 서버) 직접 접근 - 요청시 진짜 데이터가 있는 서버

  • 웹브라우저가 요청할 때마다 실제 서버에 접근하게되면 속도가 매우 느려짐

표현된 시간은 가상의 시간

 

(2) 프록시 캐시 도입(캐시서버)

  • 중간에 서버를 도입해서 요청 시 원서버에 접근하는 것이 아니라 캐시서버에 접근하여 데이터를 전송 받음
  • 물론 최초 요청(캐시서버에 데이터가 없는 경우)은 원서버에서 데이터를 가져와야하고 그 이후부터는 캐시 서버에 저장된 데이터를 받게 됨
  • 웹 브라우저에 있는 캐시(로컬 캐시) : private 캐시
  • 프록시 캐시 서버: public 캐시

표현된 시간은 가상의 시간

(3) 캐시 지시어 - 기타

  • Cache-Control: public : 응답이 public 캐시에 저장 되어도 됨
  • Cache-Control: private : 응답이 사용자만을 위한 값, private 캐시에 저장(기본값)
  • Cache-Control: s-maxage : 프록시 캐시에만 적용되는 max-age
  • Age: 60(HTTP 헤더) : 오리진 서버에서 응답 후 프록시 캐시 내에 머문 시간(초)

5. 캐시 무효화

1) 캐시 지시어 - 확실한 캐시 무효화 응답

  • 캐시를 적용하지 않아도 웹 브라우저가 GET요청인 경우에는 임의로 캐시를 해버리게 됨(휴리스틱하게 한다?)
  • 해당 페이지를 정말 캐시가 되면 안되라고 지시할 경우 명령어를 다 넣어줘야함
  • Cache-Control: no-cache, no-store, must-revalidate
  • Pragma:no-cache (HTTP 1.0 이전 브라우저에서 요청이 올 것을 대비)

(1) Cache-Control: no-cache

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

(2) Cache-Control: no-store

  • 데이터에 민감한 정보가 있으므로 저장하면 안됨(메모리에서 사용 후 최대한 빨리 삭제)

(3) Cache-Control: must-revalidate

  • 캐시 만료 후 최초 조회시 원 서버에 데이터를 검증해야함
  • 원 서버 접근 실패 시 반드시 오류가 발생해야함(504 Gateway Timeout)
  • 캐시 유효 시간 내에 요청은 캐시를 사용

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

2) no-cache vs must-revalidate

(1) no-cache

  • 웹 브라우저에서 no-cache+ETag를 달고 요청을 하면 프록시 캐시가 아닌 원래의 서버에서 응답을 함
  • 만약 원서버에 접근이 불가능할 경우(여러 외부의 요인) 오류가 아닌 프록시 데이터가 가진 데이터(오래된 데이터라도)를 응답하도록 프록시 서버가 세팅 되어있음
  • 요청했던 데이터가 최신 데이터가 아닐 수 있음(예 - 통장 잔고의 데이터가 과거의 것으로 출력되면 문제가 발생 될 수 있음)

 

(2) must-revalidate

  • 원 서버에 접근이 불가능할 경우 무조건 504 Gateway Timeout 에러를 발송함
  • 잘 발생하지는 않지만 확실하게 하려면 해당 캐시 지시어까지 포함해야 완벽한 캐시 무효화를 할 수 있음