모든 개발자를 위한 HTTP 웹 기본지식 - 챕터 8

Chooooo·2022년 11월 12일
0
post-thumbnail

이 글은 강의 : 김영한님의 - "[모든 개발자를 위한 HTTP 웹 기본지식]"을 듣고 정리한 내용입니다. 😁😁


캐시와 조건부 요청과 관련된 헤더들과 동작들에 대해서 알아보자.

캐시

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

사용법

조건부 요청 헤더(캐시 지시어)

(캐시와 조건부 요청 헤더)

캐시는 캐시 지시어라는 헤더필드를 이용하여 제어할 수 있다.
Cache-Control이라는 **헤더 필드에 원하는 값을 지정해서 캐시의 수명이나 로직을 정의한다.**

cache-control -> 캐시 지시어

🎃 Cache-Control: max-age

  • 캐시에 유효시간을 줘서 해당 시간 내에는 서버에 요청하지 않고, 브라우저 캐시에 있는 해당 자원을 활용한다. (초 단위)
  • cache-control: max-age=60 : 60초간 유효하다.

🎃 Cache-Control: no-cache

  • 데이터는 캐시해도 되지만, 항상 Origin 서버에 검증하고 사용해야 한다.
  • 프록시 캐시 서버에서 원 서버에 접속이 일시적 오류로 안되는 경우, 오래된 데이터라도 보여주자는 정책으로 200 OK를 응답한다.

🎃 Cache-Control: must-revalidate

  • 캐시 만료후 최초 조회시 Origin 서버에 검증해야 한다.
  • Origin 서버에 접근이 실패하는 경우 무조건 오류를 발생해야 한다.
    504 Gateway Timeout

🎃 Pragma: no-cache

  • HTTP 1.0에서 사용되는 하위 호환 방식의 필드

검증 헤더

캐시의 유효시간이 만료된 경우 원 서버에 다시 자원을 요청하는데, 만약 아직도 자원이 변경되지 않았다면, 여전히 자원을 새로 반환할게 아니라 변경되지 않았다고 응답해 브라우저 캐시의 자원을 재활용하는게 효율적이다. 이를 돕기 위해 검증헤더가 사용되며, 이러한 검증 헤더는 두 가지 방식이 있다.

검증 헤더!

Last-Modified / if-modified-since

해당 헤더에 자원의 마지막 수정 시간 정보를 작성함으로써 두 정보를 비교해 캐시 활용 여부를 결정할 수 있다.



🎃 최초 자원 요청시 서버측에서는 유효시간(60초)와 Last-Modified로 해당 자원(star.jpg)가 마지막으로 수정된 날짜를 UTC 기준으로 작성하여 보내준다.

🎃 클라이언트측은 응답결과를 캐시에 저장하여 해당 자원은 60초간은 서버에 요청하지 않고 브라우저 캐시에 저장된 자원을 활용한다.

🎃 유효시간이 만료되면 다시 서버에 자원을 요청하는데 이 때 if-modified-since라는 검증헤더에 서버측으로부터 받았던 Last-Modfied 날짜를 작성해서 전달한다.

🎃 서버측에서는 해당 자료의 최종 수정일과 클라이언트가 전송한 최종 수정일을 비교하여 변경이 되었을 경우 새로운 자원을 다시 최종변경일과 유효시간과 함께 전송하고, 만약 아직 자원이 변경되지 않았다면 다시 새로운 유효시간(max-age)를 작성해 304 Not Modified 상태코드를 Message Body 없이 반환하여 기존 브라우저 캐시의 자원을 활용하도록 한다.

Body 미포함이 핵심. -> 리다이렉션 헤더만 전송하면 돼

주의점: 해당 검증 헤더는 1초 이하(0.5초,...)의 시간은 저장하지 못하기 때문에, 실제로 0.5초뒤에 자료가 변경되었다 하더라도 감지할 수 없다. 또한, 데이터를 수정했다가 원복한 경우에도 이를 감지하지 못한다.

If-None-Match / ETag

캐시를 오로지 서버에서 컨트롤함으로써 블랙박스처럼 정보를 은닉하고자 할 때 사용하는 검증 헤더이다. Last-Modified 대신 ETag(Entity Tag)라는 검증 헤더를 이용하여 서버측에서 지정한 임의의 버전(혹은 이름)등을 제공하여 관리한다.

🎃 서버측에서는 ETag 라는 검증 헤더에 자원에 맞는 값을 작성하여 반환한다.

🎃 클라이언트의 캐시에서는 해당 ETag 값을 저장한다.

🎃 해당 자원의 유효시간(max-age)이 만료되어 다시 서버에 요청을 할 경우 저장해뒀던 ETag를 If-None-Match에 작성하여 보낸다.

🎃 서버측에서는 해당 자원의 현재 ETag값과 전달받은 Etag값을 비교하여 같을 경우 304 Not Modified 상태코드를 반환하고, 값이 다를 경우 새로운 ETag와 함께 200 OK 상태코드를 반환한다.

이 방식은 ETag 생성 로직을 온전히 서버에서 관리하기에 Last-Modified처럼 변경날짜같은게 외부에 노출되지 않는다. 그리고 클라이언트에서는 이런 생성로직이나 캐시 메커니즘에 대해서도 이해할 필요 없이 그저 값을 사용하기만 하면 된다.

프록시 캐시


  • 클라이언트들과 Origin 서버의 거리가 너무 멀리 떨어져있어서 응답시간이 많이 소요되는 경우 고려되는 기술로 클라이언트들과 원 서버 사이에 프록시 캐시 서버를 둠으로써 응답시간을 줄이는 방식이다.
    클라이언트로부터 요청되는 자원에 대해 프록시 캐시서버에서 캐시를 저장하여 제공함으로써 여러 사람이 찾는 자료일수록 이미 캐시에 등록되어 있기에 빠른속도로 자원을 받을 수 있다.
    클라이언트에서 사용되는 캐시는 해당 클라이언트에서만 사용되기에 private 캐시라 부르고 프록시 캐시 서버에서 사용되는 캐시는 여러 클라이언트들에게 노출되야 하기에 public 캐시라 부른다.

캐시 무효화

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

  • 통장 잔고와 같이 캐시활용이 되서는 안되는 서비스의 경우 캐시를 확실하게 무효화해야하는데, 하위호환까지 고려해서 위와 같이 작성을 하면 된다.

🎃 확실한 캐시 무효화 응답

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

🎃 no-cache , must-revalidate 혼용해야 하는 이유

  1. no-cache
  • no-cache는 항상 원 서버에 검증을 하도록 하는 속성이다.
  • no-cache는 원 서버에 접속이 안되는 경우 오래된 데이터라도 보여주자는 정책으로 200 OK를 응답한다.
  • 즉, 매번 원 서버에 검증을 요청은 하지만, 접속을 실패한다고 오류를 반환하지는 않고 기존 캐시를 활용하도록 하기에 문제가 된다.
  1. must-revalidate
  • must-revalidate는 원 서버에 접속이 불가능한 경우 무조건 오류를 반환한다.
  • must-revalidate는 캐시 유효시간(max-age)이 남아있다면 원 서버에 요청을 하지 않고, 캐시를 재활용한다.
  • 즉, 유효시간에 따라서 원 서버에 검증을 요청하지 않아서 캐시를 재활용하는 문제가 발생할 수 있다.

정리하면,
no-cache로 매번 원 서버에 검증을 요청하도록 하고, must-revalidate로 접속이 실패할 경우 무조건 오류를 발생하도록 해서 캐시를 사용하지 않도록 한다. 거기에 Pragma 헤더를 추가해 1.0 이하 버전의 하위호환성도 적용한다.

profile
back-end, 지속 성장 가능한 개발자를 향하여

0개의 댓글