HTTP Cache와 NextJS Page Router 캐싱 정리

HTTP 캐싱에 대한 내용 정리 및 NextJS PageRouter에서 캐싱 방식에 대해서 정리했습니다.


Http 캐시

유저와 서버 간의 캐싱 상호작용

  1. 초기 요청: 사용자가 웹페이지에 처음 접속하면 서버는 해당 페이지의 모든 자원(HTML, CSS, JS, 이미지 등)을 응답과 함께 보냅니다. 이때 서버는 각 자원에 대해 적절한 캐시 정책을 설정해 둡니다.
  2. 재요청 시: 사용자가 같은 페이지에 다시 접속하면, 브라우저는 캐시에 저장된 자원을 사용하여 페이지를 로드합니다. 필요한 경우 브라우저는 서버에 조건부 요청을 보내 자원이 최신 상태인지 확인합니다.
  3. 캐시된 자원의 만료: 서버가 설정한 캐시 유효 기간이 지나면, 브라우저는 해당 자원을 새로 요청하게 됩니다. 이때 서버는 새 자원을 제공하거나, 자원이 변경되지 않았음을 알려 캐시를 재사용하게 할 수 있습니다.
  • Cache-Control 옵션

    1. public

    • 설명: 응답을 모든 캐시에 저장할 수 있음을 나타냅니다. 공유 캐시(예: CDN, 프록시 서버)와 브라우저 캐시 모두에 저장될 수 있습니다.
    • 예시: Cache-Control: public

    2. private

    • 설명: 응답을 단일 사용자에 대해서만 캐시할 수 있음을 나타냅니다. 브라우저 캐시에만 저장되며, 공유 캐시에는 저장되지 않습니다.
    • 예시: Cache-Control: private

    3. no-store

    • 설명: 응답을 전혀 캐시하지 않음을 의미합니다. 이 디렉티브는 요청 또는 응답에 대해 어떠한 캐시도 저장하지 않아야 함을 지시합니다. 요청할 때마다 항상 서버에서 새 데이터를 가져옵니다.
    • 예시: Cache-Control: no-store

    4. no-cache

    • 설명: 응답을 캐시에 저장할 수 있지만, 재사용 전에 서버에 검증해야 함을 의미합니다. 캐시에 저장된 데이터가 유효한지 확인하는 과정을 거칩니다.
    • 예시: Cache-Control: no-cache

    5. max-age=<seconds>

    • 설명: 캐시에 응답을 저장할 수 있는 최대 시간(초 단위)을 지정합니다. 이 시간이 지나면 캐시는 만료된 것으로 간주되고, 다시 서버에서 데이터를 가져오게 됩니다.
    • 예시: Cache-Control: max-age=3600 (1시간 동안 캐시 가능)

    6. s-maxage=<seconds>

    • 설명: 공유 캐시(예: 프록시 서버)에서 응답을 저장할 수 있는 최대 시간을 지정합니다. 이 디렉티브는 max-age를 덮어씁니다. 클라이언트 측 캐시에는 적용되지 않습니다.
    • 예시: Cache-Control: s-maxage=600 (10분 동안 공유 캐시에 캐시 가능)

    7. must-revalidate

    • 설명: 캐시된 데이터가 만료되면, 반드시 서버에 검증 요청을 보내야 함을 의미합니다. 서버가 응답을 다시 확인하지 않고는 재사용할 수 없습니다.
    • 예시: Cache-Control: must-revalidate

    8. proxy-revalidate

    • 설명: must-revalidate와 유사하지만, 이 디렉티브는 프록시 서버에서만 적용됩니다. 공유 캐시에서만 만료된 데이터를 다시 검증해야 함을 의미합니다.
    • 예시: Cache-Control: proxy-revalidate

    9. no-transform

    • 설명: 중간 프록시 서버가 응답 콘텐츠를 변경하지 않도록 합니다. 예를 들어 이미지 포맷 변환 등의 작업을 허용하지 않습니다.
    • 예시: Cache-Control: no-transform

    10. immutable

    • 설명: 응답이 절대로 변경되지 않을 것임을 나타냅니다. 이 경우, max-age 기간 동안 캐시된 데이터를 서버에 검증하지 않고 재사용할 수 있습니다.
    • 예시: Cache-Control: immutable

    11. stale-while-revalidate=<seconds>

    • 설명: 캐시된 데이터가 만료된 경우에도, 지정된 시간 동안 해당 데이터를 사용하면서 백그라운드에서 재검증할 수 있습니다.
    • 예시: Cache-Control: stale-while-revalidate=120 (캐시가 만료된 후 2분 동안 재검증 없이 사용 가능)

    12. stale-if-error=<seconds>

    • 설명: 서버 오류가 발생한 경우, 지정된 시간 동안 만료된 캐시를 사용할 수 있습니다.
    • 예시: Cache-Control: stale-if-error=300 (오류 발생 시 5분 동안 만료된 캐시 사용 가능)

    13. max-stale=<seconds>

    • 설명: 클라이언트가 만료된 캐시를 여전히 사용할 수 있는 시간을 지정합니다. 이 디렉티브는 클라이언트 측에서만 사용됩니다.
    • 예시: Cache-Control: max-stale=600 (캐시가 만료된 후 10분 동안 사용할 수 있음)

    14. min-fresh=<seconds>

    • 설명: 캐시된 응답이 최소한 지정된 시간 동안은 유효해야 함을 나타냅니다. 이 디렉티브는 클라이언트 측에서 서버에 요청 시 사용됩니다.
    • 예시: Cache-Control: min-fresh=60 (1분 이상 유효해야 함)

자주 쓰이는 옵션 설명

  • public, max-age=3153600

    → 중간 서버에도 캐싱될 수 있도록 하고, 브라우저에 1년 동안 캐싱되도록 한다. 유효성 검사는 서버에 요청하고, 바뀌지 않았으면 304를 돌려받은 뒤 캐싱된 데이터를 사용한다.

  • private

    → 중간 서버에 캐싱되지 않고, 오직 브라우저에만 캐싱될 수 있도록 한다. 서버로부터 캐싱을 얼마나 할 것인지 정해진 것이 없기 때문에 브라우저만다 다르게 동작하게 된다.

  • no-cache

    → 브라우저에 캐싱할 수 있지만, 반드시 서버에서 304 응답이 와야지만 그 캐시를 사용할 수 있다. 브라우저에 캐싱을 하지 않는다는 의미 X

  • no-store

    → 브라우저에 캐싱할 수 없음. 반드시 리소스를 요청하게 되면 서버로 매번 요청함.

  • must-revalidate

    → 캐싱이 만료되었으면 반드시 서버로 캐싱된 데이터가 유효한지 검증 받아야한다는 옵션.

  • immutable

    → 캐싱할 수 있는 시간이 명시되어 있을 때, 그 시간 동안은 서버에 유효성 검증을 하지 않고, 바로 사용할 수 있다는 것을 의미함

NextJS Page Router의 캐싱 방식

  • 빌드될 때마다 파일에 고유한 이름이 생기기 때문에, 빌드할 때만 정해지는 파일은 재요청 받지 않도록 설정한다. (cache-control: public, max-age=31536000, immutable)

    • html, js, css, 각종 이미지 파일들 모두 포함

    cache-control 디렉티브의 의미

    1. public:
      • 이 디렉티브는 응답을 모든 캐시(공유 캐시와 브라우저 캐시 모두)에 저장할 수 있음을 나타냅니다. 즉, 프록시 서버, CDN, 브라우저 등의 캐시 모두가 이 응답을 캐시할 수 있습니다.
      • 이는 특정 사용자에게만 해당되는 private과 반대되는 개념으로, 모든 사용자가 동일하게 접근할 수 있는 콘텐츠에 적합합니다.
    2. max-age=31536000:
      • 이 디렉티브는 캐시된 응답이 유효한 최대 시간을 초 단위로 지정합니다. 여기서 31536000초는 정확히 1년을 의미합니다.
      • 따라서 이 응답은 캐시에 1년 동안 저장되며, 그 기간 동안에는 서버에 다시 요청하지 않고도 캐시에서 직접 제공될 수 있습니다.
    3. immutable:
      • 이 디렉티브는 응답이 절대로 변경되지 않을 것임을 나타냅니다. 즉, 이 자원은 한 번 캐시에 저장되면 유효 기간(max-age)이 끝날 때까지 절대로 변경되지 않으므로, 클라이언트나 캐시 서버는 이를 다시 검증할 필요가 없습니다.
      • 이 설정은 캐시된 자원이 새로고침이나 다른 조건부 요청 없이도 재사용될 수 있도록 보장합니다.
  • ISR 방식으로 생성되는 페이지에 대해서는 revalidate가 중간 서버에 캐싱될 수 있는 s-max-age가 된다. (cache-control: s-maxage=10, stale-while-revalidate)

    cache-control 디렉티브의 의미

    • s-maxage=10:
      • 이 디렉티브는 공유 캐시에서 응답을 캐시할 수 있는 최대 시간을 10초로 지정합니다. 이 시간 동안은 공유 캐시가 해당 응답을 재사용할 수 있습니다.
      • 클라이언트(브라우저) 캐시에는 적용되지 않고, 공유 캐시에만 영향을 미칩니다.
    • stale-while-revalidate:
      • 이 디렉티브는 캐시된 응답이 만료된 경우에도, 새 응답을 가져오는 동안 만료된 캐시된 응답을 계속 사용할 수 있도록 합니다.
      • 즉, 새로운 데이터를 가져오는 동안 사용자는 이전(만료된) 데이터를 계속 볼 수 있으며, 이로 인해 사용자 경험이 중단되지 않고, 새 데이터를 가져오는 백그라운드 작업이 완료된 후에만 업데이트된 내용이 반영됩니다.
  • 이러한 캐시 정책으로 인해서 NextJS에서는 SSR과 자체 API를 제외하고는 캐시 정책을 개발자가 설정해줄 수 없다.

레퍼런스

웹 서비스 캐시 똑똑하게 다루기

next.config.js Options: headers