캐시 무효화

2024. 11. 23. 20:11프로그래밍/Front-end

캐시 무효화를 위한 응답 헤더 설정법

Cache-Control: no-cache, no-store, must-revalidate  
Pragma: no-cache  
💡 `Expires: 0` 응답 헤더를 함께 사용하는 경우도 있는데,
 이는 문법 위반이며 몇몇 소프트웨어와 충돌할 가능성이 있으므로 사용을 지양해야 함 
 (응답을 받는 쪽에선 대비 필요)  

(우선순위 순. 함께 쓰였다면 후순위는 무시됨)

  • Cache-Control: 캐시의 신선도를 관리하기 위한 헤더. 문서가 만료되기 전까지 얼마나 오랫동안 캐시될 수 있게 할 것인지 서버가 설정할 때 사용. (HTTP/1.1)
    • no-store: 응답을 로컬 저장소에 저장하지 말라는 의미. (메모리에서만 사용하고 최대한 빨리 삭제하라)
    • no-cache: 로컬 캐시 저장소에 응답을 저장하지만, 반드시 항상 원 서버에 검증하고 사용해야 한다.
      정확히는 “Do not serve from cache without revalidation”라고 이해해야 함.
    • must-revalidate: 사본이 만료된 후 최초로 조회했을 땐 원 서버에 검증하고 사용해야 함
    • max-age=<s>: 캐시의 유효 기간(초 단위). 유효 기간이 다 되면 원 서버에 재검증하고 사용해야 함
      • max-age=0no-cache는 대부분의 브라우저에서 동일한 뜻을 가짐
      • no-store, no-cache, must-revalidate를 썼다면 max-age를 함께 쓰지 않아야 함. 서로 대치되는 의미이기 때문임
  • Pragma: no-cache: HTTP/1.0 하위 호환용
  • Expires: <date>: 캐시의 만료 날짜를 절대 시각으로 명시. Cache-Control: max-age=<s>와 함께 쓰였다면 Expires 헤더가 무시됨
💡 `no-store`가 있는데 `no-cache`까지 필요한 건, IE10과 그 이전 버전에선 `no-cache`만 사용하기 때문  

*출처: https://learn.microsoft.com/en-us/troubleshoot/developer/browsers/connectivity-navigation/how-to-prevent-caching*  

응답에 캐시의 만료 시점에 대한 정보가 없다면? :: 휴리스틱 만료

  • 서버에서 응답을 생성할 때 Cache-Control: max-age=<s>Expires가 없었다면, 휴리스틱하게 만료 시점을 계산하게 됨

  • 다양한 휴리스틱 만료 알고리즘이 있는데, 대표적으로 LM-Factor Algorithm이 있음(Last-Modified 값을 factor로 활용하는 방법)

    • 캐시된 문서가 마지막으로 수정된 게 오래전이다?
      → 안정적인 문서일 것. 갑자기 바뀔 가능성 낮으므로 캐시에 더 오래 보관해도 괜찮을 것

    • 캐시된 문서가 최근에 수정됐다?
      → 자주 변경될 가능성이 큼. 서버와 재검사하기 전까지 짧은 기간 동안만 캐시해야 함

      Calculate fresh cycle with LM-Factor algorithm

      Research and Implementation of HTTP Caching Freshness Algorithm - Scientific Figure on ResearchGate. Available from: https://www.researchgate.net/figure/Calculate-fresh-cycle-with-LM-Factor-algorithm_fig1_300619144 [accessed 23 Nov 2024]

  • 휴리스틱 신선도 유지 기간의 상한은 보통 일주일. 보수적인 사이트는 하루 정도로 설정함

  • 만약 최종 수정 시간도 없으면, 기본값을 사용함(한 시간 ~ 하루)

Nginx 캐시 설정

캐시 무효화

    location / {  
        root /home1/irteam/deploy/dist;  
+       add_header Cache-Control "no-cache, no-store, must-revalidate";  
+       add_header Pragma "no-cache";  
        try_files $uri $uri/ /index.html;  
    }  

특정 타입의 리소스는 별도로 캐시 설정을 하고 싶다면

    location / {  
        root /home1/irteam/deploy/dist;  
        add_header Cache-Control "no-cache, no-store, must-revalidate";  
        add_header Pragma "no-cache";  
        try_files $uri $uri/ /index.html;  
    }  

+   location ~* \.(gif|jpeg|jpg)$ {  
+       add_header Cache-Control "public, max-age=86400";  
+   }  
💡
`Cache-Control: private`: End user만 개인 PC의 디스크나 메모리에 캐시를 저장할 수 있음  

`Cache-Control: public`: 모든 사용자와 공용 프락시 서버가 캐시를 저장할 수 있음. 
공용 프락시 서버에 리소스를 캐싱하면, 사용자가 자주 찾는 리소스를 원 서버에서 딱 한 번만 가져와 모든 클라이언트의 요청에 대해 공유된 사본을 제공할 수 있음 
⇒ 네크워크 트래픽 감소  

Q. 캐시의 만료 시점에 대해 딱히 지정하지 않았다가, 갑자기 캐시 무효화 하도록 설정해서 서버를 배포하면 어떻게 될까?

A.

  • 서버에서 응답을 생성할 때 캐시의 만료 시점을 휴리스틱하게 계산해서 설정했을 것임
  • 참고: RFC 7234 - Hypertext Transfer Protocol (HTTP/1.1): Caching - 4.2.2. Calculating Heuristic Freshness*
  • 만약 서버가 응답에 만료 시점을 명시하지 않았더라도, 클라이언트가 얼마나 캐시를 오래 보존할지 결정할 수 있음
    (max-stale, min-fresh, max-age 값이 설정되었는지에 따라 적절한 한계값을 계산해서 서버가 준 유효 기간을 덮어씀)
  • 서버와 클라이언트에서 결정한 캐시의 유효 기간이 지나 캐시가 만료되면, 그때 서버에 캐시를 재검증하게 됨.
    이때 Cache-Control: no-store, no-cache, must-revalidate 헤더를 포함한 응답을 받게 되어,
    로컬 저장소에 있는 캐시를 삭제함과 동시에 이후의 캐시는 저장하지 않게 됨

클라이언트에서 강제로 캐시를 갱신하는 방법

  1. 리로드(Reload)
    • 브라우저가 캐시된 리소스를 무시하고 모든 리소스를 다시 다운로드하여 페이지를 완전히 새로고침 하는 것
    • 개발자 도구를 연 상태에서 주소 표시줄 옆의 새로고침 버튼을 Windows: Ctrl, Mac: Cmd 함께 클릭하여 “캐시 비우기 및 강력 새로고침” 선택
  2. Disable cache
    • 개발자 도구 > Network > Disable cache 클릭
    • 이 옵션을 활성화하면, Request Header에 Cache-Control: no-cache , Pragma: no-cache 헤더가 포함되어 요청이 감
  3. 요청 URL에 무작위한 쿼리 문자열 추가
    • 페이지가 로드될 때 특정 리소스에 대한 요청을 다시 보내도록 할 수 있음
      (ex. img, script 태그의 src 또는 href 속성에 쿼리 문자열을 추가)
    • 브라우저는 매번 다른 URL을 사용하여 리소스를 가져오기 때문에 캐시를 무시하고 새로운 리소스를 다운로드함

참고문헌