Skip to Content
기타AWSAmplify 캐싱05. CDN 캐시와 Cache-Control 헤더 다루기

이번 편의 결과물: 홈 화면(/)에 커스텀 Cache-Control 헤더를 적용해 재배포하면, 응답의 cache-controlage 값이 설정한 시간대로 바뀝니다. · 다루는 개념: CloudFront TTL과 max-age/s-maxage 상호작용, Amplify 커스텀 헤더 설정, 정적 자산과 SSR 응답의 캐시 차이

04편에서 notice-board를 Amplify Hosting에 배포하고, 처음으로 x-cache·age·cache-control 헤더를 봤습니다. 지금까지 이 값들은 전부 Next.js가 알아서 정한 값이었습니다. 이 편에서는 Amplify 저장소 설정 파일로 그 값을 직접 바꿔봅니다. 아직 이 과목에는 홈 화면(/) 말고 다른 페이지가 없으므로, 이번 실습은 홈 화면을 대상으로 합니다.

이 편에서 만드는 파일

notice-board/ └── customHttp.yml (+, / 경로의 Cache-Control을 s-maxage=30으로 재정의)

개념 정리

max-age와 s-maxage

지시어대상의미
max-age브라우저 캐시브라우저가 응답을 몇 초 동안 다시 요청하지 않고 재사용할지
s-maxage공유 캐시(CDN 등)CloudFront 엣지가 origin에 다시 묻지 않고 몇 초 동안 응답을 재사용할지. 같이 있으면 max-age보다 우선한다

CloudFront는 엣지에 캐시된 지 얼마나 지났는지를 age 응답 헤더로 알려줍니다. ages-maxage를 넘으면 다음 요청은 origin까지 다시 갑니다.

Amplify가 헤더를 정하는 방식

Amplify Hosting은 기본적으로 origin(Next.js 컴퓨트)이 보낸 Cache-Control을 그대로 CloudFront에 전달합니다. 커스텀 헤더를 따로 정의하면 그 값이 origin의 값을 대신합니다. 이 재정의는 상태 코드가 200 OK인 응답에만 적용되고, 에러 응답에는 적용되지 않습니다.

커스텀 헤더는 두 가지 방법으로 설정합니다.

방법위치특징
Amplify 콘솔Hosting → Custom headers코드 변경 없이 즉시 설정, 저장 후 재배포 필요
customHttp.yml저장소 루트Git으로 버전 관리됨. 콘솔 설정보다 우선 적용됨

이 편에서는 저장소에 넣어 버전 관리할 수 있는 customHttp.yml 방식을 씁니다.

pattern은 경로를 정확히 지정한다

pattern에 와일드카드 없이 /만 적으면 홈 화면 경로 하나에만 적용됩니다. 나중에 다른 경로까지 넓히려면 /api/*처럼 뒤에 *를 붙입니다. 지금은 홈 화면 하나만 다루므로 /로 좁혀서 씁니다.

정적 자산과 SSR 응답의 캐시 차이

응답 종류기본 Cache-Control비고
_next/static/* 같은 불변 자산public, max-age=31536000, immutable파일명에 해시가 붙어 안전하게 영구 캐시
지금 시점의 홈 화면(완전 정적 렌더)매우 긴 s-maxage(사실상 1년)07편에서 fetch 기반 ISR로 바뀌면 값이 달라진다
동적으로 렌더된 페이지private, no-cache, no-store, max-age=0, must-revalidate사용자별 데이터가 섞이지 않도록 아예 캐시하지 않음

실습

1. 재배포 전 헤더 확인

curl -I https://main.d1234567890abc.amplifyapp.com/
HTTP/2 200 content-type: text/html; charset=utf-8 cache-control: s-maxage=31536000, stale-while-revalidate x-cache: Hit from cloudfront age: 342

cache-control이 1년에 가까운 s-maxage로 잡혀 있고, x-cacheHit from cloudfront라 이미 CDN 엣지에 캐시된 상태입니다.

2. customHttp.yml 작성

# customHttp.yml customHeaders: - pattern: '/' headers: - key: 'Cache-Control' value: 's-maxage=30'

3. 커밋과 재배포

git add customHttp.yml git commit -m "홈 화면 CDN 캐시 30초로 조정" git push

GitHub 저장소에 푸시하면 04편에서 연결한 Amplify Hosting이 자동으로 새 빌드를 시작합니다. Amplify 콘솔 → 앱 선택 → 배포 이력에서 빌드가 끝났는지 확인합니다.

4. 재배포 후 헤더 확인

curl -I https://main.d1234567890abc.amplifyapp.com/
HTTP/2 200 content-type: text/html; charset=utf-8 cache-control: s-maxage=30 x-cache: Miss from cloudfront age: 0

재배포 직후 첫 요청은 CloudFront 입장에서 새 콘텐츠이므로 x-cacheMiss from cloudfront, age0입니다. cache-control은 origin이 보낸 값 대신 customHttp.yml에 적은 s-maxage=30으로 바뀌어 있습니다.

30초 안에 같은 요청을 다시 보내면 x-cache: Hit from cloudfront와 함께 age가 경과 시간만큼(예: 12) 나오고, 30초가 지난 뒤 요청하면 다시 age: 0으로 리셋됩니다.

이 s-maxage=30 오버라이드는 07편에서 홈 화면에 60초 ISR을 적용할 때 그대로 두면 origin이 실제로 보내는 값을 가려버립니다. 07편 실습 전에 이 오버라이드를 제거하거나 값을 조정하는 단계가 포함되어 있으니, 지금은 그대로 둡니다.

직접 해보기

  1. s-maxage 값을 5로 낮춰 재배포한 뒤, 5초 간격으로 curl -I를 3~4번 반복해 age가 자주 0으로 리셋되는 것을 관찰해보세요.
  2. pattern/에서 /no-such-page처럼 실제로 없는 경로로 바꿔 재배포하면, 홈 화면의 cache-control이 다시 원래 값(1년에 가까운 s-maxage)으로 돌아오는지 확인해보세요.

정답 보기

s-maxage=5로 재배포한 뒤 5초보다 짧은 간격으로 요청하면 age0, 1, 2처럼 쌓이다가, 5초를 넘긴 요청에서 다시 age: 0으로 리셋되며 x-cacheMiss from cloudfront 또는 RefreshHit from cloudfront로 바뀝니다. pattern이 실제 요청 경로와 일치하지 않으면 그 커스텀 헤더는 어떤 응답에도 적용되지 않으므로, 홈 화면은 origin이 원래 보내는 값으로 돌아갑니다.

자주 하는 실수

증상원인고치는 법
customHttp.yml을 고쳤는데 헤더가 그대로임재배포를 안 함커밋 후 push해서 Amplify 자동 배포를 트리거한다
404 같은 에러 페이지에도 캐시 헤더가 적용될 것으로 기대Amplify는 200 OK 응답에만 커스텀 Cache-Control을 적용에러 캐싱이 필요하면 별도 pattern으로 상태 코드를 분리해 다룬다
콘솔에서 설정한 값과 customHttp.yml 값이 달라 헷갈림저장소의 customHttp.yml이 콘솔 설정보다 항상 우선 적용됨두 곳을 동시에 쓰지 말고 한쪽만 유지한다

확인 문제

문제 14지선다
Cache-Control의 max-age와 s-maxage 중, CloudFront 같은 공유 캐시가 우선적으로 따르는 지시어는 무엇인가
문제 24지선다
Amplify가 origin의 Cache-Control 헤더를 무시하고 커스텀 헤더 값을 적용하는 조건은
문제 34지선다
재배포 직후 첫 요청에서 x-cache가 Miss from cloudfront로 나오는 이유는
문제 44지선다
customHttp.yml과 Amplify 콘솔의 Custom headers 설정이 동시에 있을 때 적용 우선순위는

참고 자료

Last updated on