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

yiwoojung·2023년 9월 1일
0

캐시 기본 동작

캐시가 없을 때

1. 브라우저가 요청
2. 서버 응답 1.1m
    1. header 0.1m
    2. body 1.0m
3. 웹브라우저에 표시
4. 또 요청
5. 또 내려줌 1.1m
6. 또 그림
  • 데이터가 변경되지 않아도 계속 네트워크를 통해서 데이터를 다운받아야 함
  • 인터넷 네트워크는 매우 느리고 비쌈
  • 브라우저 로딩 속도가 느림
  • 사용자 경험 느림

캐시가 있을 때

1. 브라우저 요청
2. 서버 응답 
    1. 서버에서 캐시관련된걸 설정해줘야 함
    2. http header
        1. cache-control: max-age=60
            - 캐시가 유효한 시간
3. 응답 결과를 웹브라우저 캐시 저장소에 저장
4. 또 요청
5. 캐시에서 조회
6. 보여줌
  • 캐시 덕분에 캐시 가능 시간동안 네트워크를 사용하지 않아도 됨
  • 비싼 네트워크 사용량을 줄일 수 있다
  • 브라우저 로딩 속도 매우 빠름
  • 사용자 경험 빠름
  • ex) 브라우저에서 이미지를 요청 받을 때
  • 데이터가 변경되지 않았다면 네트워크를 사용하지 않고 브라우저 캐시에 저장해둔 데이터를 빠르게 가져옴
  • 한번 들어갔던데 다시들어가면 굉장히 빠르게 열리는데 이제 캐시 덕분임

캐시 시간 초과

1. 캐시 유효 시간 검증 후 
2. 다시 요청
3. 캐시 데이터 받아서 응답 결과를 다시 캐시에 저장
  • stale하다
  • 캐시 유효 시간이 초과하면 서버를 통해 데이터를 다시 조회하고 캐시를 갱신한다
  • 이때 네트워크 다운로드가 다시 발생

그런데 이때 만약 클라이언트랑 서버가 가진 데이터가 같다면 다시 받아야 할까?

  1. 서버에서 기존 데이터를 변경했다면?
    ⇒ 다시 보여주면 된다

  2. 서버에서 기존 데이터를 변경하지 않았다면?
    • 캐시 만료 후에도 서버에서 데이터를 변경하지 않았을 경우
    • 저장해 두었던 캐시를 재사용할 수 있다 😁
    • !단 클라이언트의 데이터와 서버의 데이터가 같다는 사실을 확인할 수 있는 방법 필요!

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

검증 헤더(Validator)

  • 캐시 데이터와 서버 데이터가 같은지 검증하는 데이터 (응답 헤더)
  • Last-Modified: Thu, 04 Jun 2020 07:19:24 GMT
  • ETag: “v1.0”

조건부 요청 헤더

  • last-modifiedetag를 활용해서 클라이언트에서 서버로 요청할 때 조건부 요청헤더를 만들어서 보내면 된다 (요청 헤더)
    • 이 데이터가 맞냐 안맞냐 물어보는거
  • 검증 헤더로 조건에 따른 분기를 서버에 요청
  • 조건이 만족하면 200
  • 조건이 만족하지 않으면 304 not modified
  • If-Match / If-None-Match: ETag 값 사용
  • If-Modified-Since / If-Unmodified-Since: Last-Modified 값 사용

특징

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


예시1 - Last-Modified, If-Modified-Since

검증 헤더 Last-Modified

  • 데이터가 마지막에 수정된 시간
  • 클라이언트에서 http 요청을 보낼 때 캐시가 가지고 있는 데이터 최종 수정일이 있다면 조건부 요청 사용

조건부 요청 헤더 If-Modified-Since

  • 변경이 일어났는가?
  1. if-modified-since: 데이터 최종 수정일을 서버에 보냄
  2. 서버에서 데이터가 수정됐는지 안됐는지를 알 수 있다
  3. 이후에 데이터가
    1. 변경되지 않았다면 (false)
      • ex) 캐시: 2020년 11월 10일 10시 ⇒ 서버: 2020년 11월 10일 10시
      • 변경이 안되었으므로 false ⇒ 304 not modified ⇒ 캐시로 redirection
      • header 데이터만 전송, body 미포함 (http body가 없음)
      • 전송 용량은 header 용량과 같음
      • 네트워크 부하가 줄어든다
    2. 변경 되었다면 (true)
      • ex) 캐시: 2020년 11월 10일 10시 ⇒ 서버: 2020년 11월 10일 11시
      • 200 ok, body를 포함한 모든 데이터 전송
      • 전송 용량은 header 용량 + body 용량
  4. 캐시를 다시 세팅하거나 불러와서 사용

단점

  1. 1초 미만 단위로 캐시 조정이 불가능
  2. 날짜 기반의 정해진 로직 사용
    • 데이터를 수정해서 날짜가 다르지만, 같은 데이터를 수정해서 데이터 결과가 똑같은 경우 날짜가 달라졌으므로 변경된 것으로 간주하게 됌

서버에서 별도의 캐시 로직을 관리하고 싶은 경우라면
서버에서 캐시 매커니즘을 컨트롤할 수 있는 방법이 있다

바로 etag다 entity tag


예시2 - ETag, If-None-Match

검증헤더 ETag, 조건부 요청 헤더 If-None-Match

  • Etag(Entity Tag)
  • 캐시용 데이터에 임의의 고유한 (버전) 이름을 달아둠
    • Etag: “2q43r”
  • 데이터가 변경되면 이 이름을 바꾸어서 변경함(Hash를 다시 생성)
    • ex) 파일을 해시 알고리즘에 넣어서 해시 결과로 받을 수 있는데 파일의 컨텐츠가 같으면 같은 hash 값이 나온다
  • 클라이언트에서는 단순하게 ETag만 보내서 같으면 유지, 다르면 다시 받기!
  • 매치가 됐다? ⇒ 실패 ⇒ 304 Not Modified ⇒ header만 전송
  • 캐시 제어 로직을 서버에서 완전히 관리
  • ⇒ 클라이언트는 캐시 메커니즘을 모른다
  • 클라이언트는 단순히 이값을 서버에 제공

캐시와 조건부 요청 헤더

cache-control

캐시 지시어(directives)

  • cache-control: max-age
    • 캐시 유효시간 = 얼마동안 유효할거냐
    • 초 단위로 입력 가능(유연함)
  • cache-control: no-cache
    • 데이터는 캐시해도 되지만 항상 origin 서버에 검증하고 사용
      • 원 origin 서버란?
        • 중간 캐시 서버(캐시 proxy 서버)에서는 하면 안되고 진짜 뒤에있는 origin 서버까지 가서 해야한다는 뜻
    • 항상 조건부 요청을 해서 서버에 이 로컬 캐시 데이터가 바꼈는지 안바꼈는지 검증을 하고 써!
  • cache-control: no-store
    • 데이터에 민감한 정보가 있으므로 저장하면 안됨
    • 메모리에서 사용하고 최대한 빨리 삭제하세요!
  • cache-control: public
    • 응답이 public cache에 저장되어도 됨
      • public cache : 중간에서 공용으로 사용하는 프록시 캐시 서버
  • cache-control: private (기본값)
    • 응답이 해당 사용자만을 위한 것임
    • private cache에 저장해야함
      • private cache: 내 웹 브라우저, 로컬에 저장되는 캐시
    • ex) 로그인한 사용자 정보
  • cache-control: s-maxage
    • 프록시 캐시(public 캐시)에만 적용되는 max-age
  • age:60(http 헤더)
    • origin 서버(원 서버)에서 응답 후 프록시 캐시 내에 머문 시간(초)

pragma

캐시 제어(하위 호환)

  • Pragma: no-cache
  • http 1.0 하위 호환 때문에 사용하기도 하지만 거의 사용하지 않음

expires

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

  • expires: Mon, 11,
  • 캐시 만료일을 정확한 날짜로 지정
  • http 1.0부터 사용
  • 지금은 더 유연한 cache-control: max-age 권장
  • cache-control: max-age와 함께 사용하면 expires는 무시된다

프록시 캐시

  • CDN

원 서버(=origin 서버) 직접 접근

한국 클라이언트에서 미국에 있는 원 서버에 접근하기위해서 0.5초가 걸린다고 가정해보자.

그럼 넘 오래 걸리니까 프록시 캐시를 도입하게 되었다

프록시 캐시 서버를 한국 어딘가에 넣어놓고 요청이 오면 미국에 있는 원 서버에 직접 접근하는게 아니라 한국 서버를 거쳐서 들어오도록 한다

웹 브라우저가 들어오면 원서버가 아닌 프록시 캐시 서버를 요청하면 응답시간이 매우 빨라진다

ex)

유투브 로딩속도

-  이상한 나라의 콘텐츠 엄청 느림 ⇒ 자주 사용하지 않아서 캐시가 없다
-  한국 콘텐츠? 로딩속도 빠름 ⇒ 한국 어딘가에 있는 서버를 이용하는 것임 

현재는 다 이런 서비스를 이용하기 때문에 응답이 빠른 것이다

  1. 보통 첫번째 유저는 느리고 한번 다운로드 받아놓으면 두번째 유저부터는 빠름
  2. 뒤에서 캐시에 밀어넣는 방법도 있음

여기서

중간에서 공용으로 사용하는 프록시 캐시 서버public cache 라고 함

웹브라우저나 로컬에 저장되는 캐시private cache라고 함


캐시 무효화

캐시를 적용 안해도 웹브라우저들이 get 요청이 경우에는 임의로 캐시를 해버리기도 한다

그래서 만약 이 페이지는 진짜 캐시가 되면 안된다면! 확실하게 캐시 무효화를 해줘야 한다

  • ex) 사용자의 통장잔고.??

cache-control에 확실한 캐시 무효화를 할 수 있는 응답이 있는데 다음을 꼭 넣어줘야 한다!

cache-control: no-cache, no-store, must-revalidate
pragma: no-cache
  • 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

서버가 에러가 났을 때 처리하는 방식이 다름

  • must-revalidate => 항상 오류가 발생
  • no-cache => 200으로 내고 오래된 데이터라도 보여준다.(no-cache 정책)

  1. no-cache나 must-revalidate + etag로 서버에 캐시를 요청한다.
  2. 프록시 캐시 서버가 봤을 때 처리하지 못하는 거라면 원서버에 요청한다.
    • 만약 순간 네트워크가 단절된다면? 원서버에 접근이 불가능할 것이다.
    • 그런데 이때 오류를 내지 않고 오래된 데이터라도 보여주도록 하고 싶다면 200 으로 응답을 보내줄 수도 있다. (no-cache 정책)
    • 그런데 이때 must-revalidate 옵션이 있다면, 항상 오류가 발생해야 한다 (504 gateway timeout)
      • ex) 통장잔고 같은 경우는 이렇게 해야함
  3. 원서버에서 검증한다.
  4. 원서버는 304 not modified라고 응답한다
  5. 캐시 데이터를 사용한다.

REFERENCE

profile
프론트엔드 개발자

0개의 댓글