“새로고침했는데 왜 그대로죠?” 웹개발 캐시 오류 해결법
CSS 색상을 바꾸고 자바스크립트 오류도 고쳤는데 브라우저 화면은 여전히 이전 모습일 때가 있습니다. 새로고침을 여러 번 누르거나 서버를 재시작해도 달라지지 않으면 코드보다 먼저 웹개발 캐시가 어느 계층에 남아 있는지 확인해야 합니다.
캐시는 웹사이트를 빠르게 보여 주는 유용한 장치지만, 개발 중에는 변경 사항을 가리는 원인이 되기도 합니다. 무작정 캐시 전체를 삭제하기보다 브라우저, 서비스 워커, CDN, 서버 순서로 범위를 좁히면 로그인 정보나 작업 환경을 잃지 않고 문제를 해결할 수 있습니다.
새로고침만 반복하면 캐시 오류가 더 헷갈리는 이유
같은 주소라도 파일을 가져오는 경로는 하나가 아닙니다
사용자가 주소창에 URL을 입력하면 브라우저가 매번 원본 서버에서 모든 파일을 새로 받는다고 생각하기 쉽습니다. 실제 웹개발 환경에서는 메모리 캐시, 디스크 캐시, 서비스 워커, 프록시, CDN, 애플리케이션 서버가 차례로 응답에 관여할 수 있습니다. 어느 한 곳이라도 오래된 HTML이나 CSS를 반환하면 방금 수정한 코드가 화면에 반영되지 않습니다.
일반 새로고침은 성능을 위해 기존 리소스를 재사용할 수 있습니다. 반면 강력 새로고침은 브라우저 캐시의 영향을 줄이지만 서비스 워커나 CDN까지 반드시 갱신하는 것은 아닙니다. 그래서 Ctrl+F5를 눌렀는데도 그대로이니 코드가 틀렸다고 단정하면 엉뚱한 파일을 계속 수정하게 됩니다.
- 메모리 캐시: 현재 열린 탭과 브라우저 프로세스에서 빠르게 재사용되며, 탭을 닫으면 상태가 달라질 수 있습니다.
- 디스크 캐시: 이미지, CSS, 자바스크립트처럼 다시 쓸 가능성이 높은 파일을 저장합니다.
- 서비스 워커 캐시: 웹 애플리케이션 코드가 정한 규칙에 따라 응답을 직접 가로챌 수 있습니다.
- CDN 캐시: 사용자와 가까운 엣지 서버가 원본 서버 대신 저장된 파일을 전달합니다.
- 서버 캐시: 프레임워크의 페이지 캐시, 템플릿 캐시, 리버스 프록시 캐시가 HTML을 보관할 수 있습니다.
먼저 코드 문제와 전달 문제를 분리합니다
가장 빠른 판단법은 수정한 문자열이나 파일 해시가 실제 응답에 포함됐는지 확인하는 것입니다. 브라우저 개발자 도구의 Network 패널을 열고 해당 요청을 선택한 뒤 Response와 Headers를 봅니다. 원본 코드에는 새 문구가 있는데 응답에는 옛 문구가 있다면 렌더링보다 배포 또는 캐시 전달 경로를 의심해야 합니다.
반대로 응답에는 새 코드가 있는데 화면만 예전 상태라면 DOM 조작, CSS 우선순위, 런타임 오류를 살펴야 합니다. 코딩은 명령을 작성하는 행위인 동시에 실행 결과를 검증하는 과정입니다. 기본 개념을 다시 확인하고 싶다면 지식백과의 코딩 용어 설명도 참고할 수 있습니다.
- Network 패널을 연 상태에서 문제 페이지를 다시 불러옵니다.
- 수정한 CSS 또는 JS 파일의 요청 URL과 상태 코드를 확인합니다.
- Response에서 새로 추가한 고유 문자열을 검색합니다.
- 응답이 최신이면 렌더링 문제로, 오래됐으면 캐시·배포 문제로 분류합니다.
- 시크릿 창이나 다른 브라우저에서 같은 주소를 열어 사용자 환경 차이를 비교합니다.
캐시 문제를 해결할 때 중요한 질문은 “캐시를 어떻게 전부 지우지?”가 아니라 “어느 계층이 오래된 응답을 반환했지?”입니다. 이 질문 하나로 불필요한 서버 재시작과 재배포를 크게 줄일 수 있습니다.
브라우저 캐시부터 안전하게 범위를 좁히는 순서
로그인 정보까지 지우기 전에 요청 한 건을 검사합니다
브라우저 설정에서 방문 기록과 쿠키를 모두 삭제하는 방식은 간단하지만 비용이 큽니다. 여러 서비스에서 로그아웃되고 로컬 스토리지의 테스트 데이터도 사라질 수 있기 때문입니다. 먼저 개발자 도구를 열고 Network 패널의 Disable cache를 활성화한 상태에서 새로고침해 보세요. 이 옵션은 보통 개발자 도구가 열린 동안에만 적용되므로 일상적인 브라우징에는 영향을 덜 줍니다.
요청 행의 Size 또는 전송 정보에 memory cache, disk cache가 표시되는지도 확인합니다. 상태 코드 304는 파일 자체를 다시 내려받지 않고 기존 사본을 사용해도 된다는 서버 판단과 관련됩니다. 304가 보인다고 곧바로 오류는 아니지만, 배포 직후 파일 내용이 달라져야 하는 상황이라면 ETag와 Last-Modified 값이 적절하게 바뀌었는지 점검할 근거가 됩니다.
- 1단계: 개발자 도구를 연 뒤 Disable cache를 켜고 재현합니다.
- 2단계: 문제 리소스를 우클릭해 새 탭에서 열고 실제 내용을 확인합니다.
- 3단계: URL 끝에 임시 쿼리 문자열을 붙여 별도 요청으로 비교합니다.
- 4단계: 시크릿 창에서 확장 프로그램과 기존 저장 데이터의 영향을 줄여 봅니다.
- 5단계: 그래도 같을 때만 해당 사이트의 저장 데이터만 선택해 삭제합니다.
CSS와 자바스크립트에는 파일명 버전 전략이 필요합니다
운영 중인 웹사이트에서 사용자의 브라우저 캐시를 일일이 지우게 할 수는 없습니다. 가장 안정적인 방법은 빌드할 때 파일 내용에 따라 해시가 포함된 이름을 만드는 것입니다. 예를 들어 app.4fd821.js의 내용이 바뀌면 app.a91c07.js처럼 URL도 달라집니다. 브라우저는 이를 새 파일로 인식하므로 오래 캐시해도 새 배포가 가려지지 않습니다.
HTML은 새 해시 파일을 가리키는 출발점이므로 비교적 짧게 캐시하거나 재검증하도록 구성하고, 해시가 붙은 정적 파일은 길게 캐시하는 방식이 효율적입니다. HTML까지 오랫동안 고정 캐시하면 새 자바스크립트 파일명이 생성돼도 사용자가 이전 HTML을 받아 옛 파일만 요청할 수 있습니다. HTML과 정적 자산에 같은 캐시 정책을 적용하는 실수가 배포 후 화면 불일치의 대표 원인입니다.
| 대상 | 권장 접근 | 주의할 실수 |
|---|---|---|
| HTML 문서 | 짧은 캐시 또는 매번 재검증 | 장기간 immutable 설정 |
| 해시 포함 CSS·JS | 장기 캐시와 immutable 활용 | 내용이 바뀌어도 같은 파일명 유지 |
| 사용자별 API | 인증·개인화 특성에 맞게 제한 | 공용 캐시에 개인정보 저장 |
| 이미지·폰트 | 버전 URL과 장기 캐시 조합 | 교체 후 URL을 그대로 유지 |
Vite, webpack, Next.js 같은 빌드 도구는 정적 자산 해시 기능을 제공하지만 결과물을 직접 확인해야 합니다. 배포 폴더의 HTML이 새 파일명을 가리키는지, 서버가 과거 빌드와 새 빌드를 섞어 제공하지 않는지 살펴보세요. 프로그래밍의 범위와 실행 과정을 이해하는 데에는 프로그래밍 개념 자료도 배경지식으로 도움이 됩니다.
서비스 워커와 CDN이 원인일 때 고치는 방법
서비스 워커는 브라우저 캐시 삭제만으로 끝나지 않을 수 있습니다
PWA를 적용한 사이트라면 서비스 워커가 요청을 가로채 자체 Cache Storage의 응답을 반환할 수 있습니다. 이때 일반 캐시를 비우거나 강력 새로고침을 해도 오래된 화면이 남을 수 있습니다. 개발자 도구의 Application 패널에서 Service Workers와 Cache Storage를 확인하고, 등록된 워커의 상태와 실제 저장된 요청 목록을 함께 봐야 합니다.
흔한 고장 원인은 캐시 이름을 새 버전으로 바꾸지 않거나 activate 단계에서 이전 캐시를 제거하지 않는 것입니다. 또 cache-first 전략을 HTML에 적용하면서 갱신 경로를 마련하지 않으면 사용자는 오랫동안 옛 앱 셸을 보게 됩니다. 새 서비스 워커가 설치됐지만 기존 탭이 닫히기를 기다리는 waiting 상태도 배포가 반영되지 않은 것처럼 보이게 합니다.
- Application 패널에서 현재 제어 중인 서비스 워커의 스크립트 URL을 확인합니다.
- Update를 실행하고 새 워커가 waiting 상태인지 살펴봅니다.
- Cache Storage에서 문제 URL의 응답 날짜와 내용을 확인합니다.
- 개발 환경에서는 Unregister 후 새로고침해 서비스 워커 개입 여부를 분리합니다.
- 운영 코드에서는 캐시 버전 변경과 이전 캐시 삭제 로직을 배포합니다.
- 업데이트가 준비됐음을 사용자에게 알리고 안전하게 새로고침하는 UI를 마련합니다.
skipWaiting과 clientsClaim을 무조건 넣는 것도 정답은 아닙니다. 열린 화면이 구형 자바스크립트를 실행하는 중에 새 서비스 워커가 새 리소스를 섞어 전달하면 버전 불일치가 생길 수 있습니다. 즉시 전환이 필요한 서비스인지, 작업 중 데이터가 있는 서비스인지 판단한 뒤 업데이트 방식을 정해야 합니다.
내 컴퓨터에서는 정상인데 다른 지역만 오래된다면 CDN을 봅니다
개발자 PC에서는 최신 화면인데 특정 통신사, 지역 또는 동료의 기기에서만 이전 화면이 보인다면 CDN 엣지 캐시 가능성이 커집니다. 응답 헤더에서 Age, Via, X-Cache처럼 캐시 적중 여부를 나타내는 값을 찾고, 원본 서버의 응답과 공개 도메인의 응답을 비교합니다. 다만 헤더 이름은 CDN 사업자마다 다르므로 사용 중인 서비스 문서를 기준으로 판단해야 합니다.
CDN의 전체 purge는 즉각적인 해결처럼 보이지만 트래픽이 한꺼번에 원본 서버로 몰릴 수 있습니다. 먼저 잘못 캐시된 정확한 URL과 변형 키를 찾고 해당 경로만 무효화하는 편이 안전합니다. 쿼리 문자열, Accept-Encoding, 국가, 기기 유형이 캐시 키에 포함되는 설정이라면 같은 경로에도 여러 사본이 존재할 수 있다는 점을 놓치지 마세요.
- 원본 확인: 내부 주소나 허용된 방법으로 원본 서버의 파일 해시를 점검합니다.
- 엣지 확인: 공개 URL 응답의 헤더, 본문, Age 값을 원본과 대조합니다.
- 키 확인: 쿼리 문자열과 요청 헤더가 별도 캐시를 만드는지 확인합니다.
- 선택 무효화: 장애 파일 또는 경로만 purge하고 전파 상태를 관찰합니다.
- 재발 방지: 배포 단계에 파일명 해시와 캐시 정책 검증을 추가합니다.
운영 장애 중에는 “일단 전부 비우자”는 선택이 빠르게 느껴집니다. 그러나 문제 URL, 캐시 계층, 현재 TTL을 기록한 뒤 최소 범위만 무효화해야 원본 과부하와 재현 불가능한 장애를 피할 수 있습니다.
API 응답을 CDN에 저장할 때는 더 조심해야 합니다. 인증 쿠키나 Authorization 헤더에 따라 내용이 달라지는 응답이 공용 캐시에 섞이면 단순한 화면 오류가 아니라 보안 사고가 될 수 있습니다. Cache-Control의 public·private·no-store 의미를 구분하고, Vary 헤더가 의도한 요청 특성을 정확히 반영하는지 테스트해야 합니다.
상품 버튼이 사라진 배포 사고를 끝까지 추적해 봅니다
증상을 한 줄로 고정하면 조사 방향이 흔들리지 않습니다
가상의 쇼핑몰 팀이 오후 2시에 상품 상세 페이지의 구매 버튼 색상과 클릭 로직을 수정했다고 가정해 보겠습니다. 개발 환경과 배포 직후 담당자 PC에서는 정상인데 고객 문의 화면에는 옛 버튼이 보이고 클릭도 작동하지 않습니다. 이때 증상을 일부 사용자가 상품 상세 페이지에서 구형 CSS와 구형 JS를 받는다로 적으면 데이터베이스나 결제 API까지 성급하게 조사 범위를 넓히지 않을 수 있습니다.
담당자는 먼저 고객이 접속한 정확한 URL, 발생 시각, 브라우저, 화면 캡처를 확보합니다. 이어 같은 URL을 시크릿 창에서 열고 Network 패널로 HTML과 자산 요청을 저장합니다. HTML 응답은 새 배포 번호를 포함하지만 script 태그가 가리키는 파일명은 이전 버전입니다. 원본 서버의 HTML은 새 파일명을 가리키므로 애플리케이션 빌드 자체보다 중간 캐시가 의심됩니다.
- 증상: 구매 버튼 디자인과 동작이 동시에 과거 버전으로 나타남
- 영향 범위: 모든 사용자가 아니라 일부 지역과 모바일 회선에서 집중 발생
- 정상 항목: 원본 서버의 최신 HTML, 새 JS 파일, 결제 API 응답
- 비정상 항목: 공개 도메인에서 받은 HTML이 이전 JS 파일명을 참조함
- 유력 원인: HTML 경로에 적용된 과도한 CDN TTL 또는 무효화 누락
한 번의 수정으로 끝내지 않고 재발 조건까지 제거합니다
응답 헤더를 비교하니 문제가 발생한 HTML에는 높은 Age 값이 있고 CDN 캐시 적중 표시가 확인됩니다. 팀은 전체 캐시가 아니라 상품 상세 HTML 경로만 무효화합니다. 이후 서로 다른 네트워크에서 HTML이 새 해시의 CSS와 JS를 참조하는지 확인하고, 구매 버튼 클릭부터 주문 직전 단계까지 테스트합니다. 단순히 화면 색상이 바뀐 것만 보고 복구됐다고 판단하지 않는 이유는 구형 JS가 남아 있으면 기능 오류가 계속될 수 있기 때문입니다.
그다음 배포 설정을 조사하니 정적 파일에 적용하려던 장기 Cache-Control 규칙이 HTML에도 포함된 사실이 드러납니다. 팀은 HTML에는 재검증 정책을, 해시 파일에는 장기 캐시 정책을 분리합니다. 또한 배포 파이프라인에 공개 URL의 HTML이 현재 빌드 해시를 참조하는지 검사하는 단계를 추가합니다. 새 코드가 서버에 존재하는지만 확인하던 배포 검증을 실제 사용자 경로까지 확장한 셈입니다.
- 상품 상세 HTML의 CDN 캐시만 선택적으로 무효화합니다.
- 새 HTML이 최신 CSS·JS 해시를 참조하는지 공개 주소에서 확인합니다.
- 모바일 회선과 다른 지역 환경에서도 같은 응답이 오는지 비교합니다.
- 구매 버튼의 표시, 클릭, 옵션 선택, 요청 전송을 순서대로 검증합니다.
- HTML과 해시 자산의 Cache-Control 규칙을 분리해 다시 배포합니다.
- 배포 후 실제 도메인 응답을 확인하는 자동 테스트를 파이프라인에 추가합니다.
자동 검증은 복잡할 필요가 없습니다. 배포가 끝난 뒤 공개 페이지 HTML을 받아 현재 빌드 식별자가 포함됐는지 확인하고, 참조된 자바스크립트 URL이 200으로 응답하는지만 검사해도 큰 효과가 있습니다. 웹개발 코드는 작성하는 순간보다 사용자에게 올바른 버전이 전달될 때 비로소 기능합니다. 관련된 코딩 개념을 다른 관점에서 살펴보려면 코딩 개념 해설을 함께 읽어도 좋습니다.
사고 기록에는 “캐시 때문에 발생”이라고만 남기지 않습니다. 잘못된 규칙이 적용된 경로, 당시 TTL, 확인한 응답 헤더, 무효화 범위, 배포 검증의 빈틈을 구체적으로 적습니다. 다음 배포에서 담당자가 버튼을 수정하자 파일 해시가 자동으로 바뀌고, HTML은 즉시 새 파일을 참조하며, 공개 URL 검사도 통과합니다. 고객의 브라우저 데이터를 지워 달라고 요청하지 않아도 새 기능이 전달되는 상태가 이 문제 해결의 진짜 완료 지점입니다.

- 이전글여름 코딩 환경: 노트북 발열로 느려진 웹개발 살리기 26.08.21
- 다음글VS Code 숨은 기능을 쓰면 웹개발 코딩 속도가 달라진다 26.08.19
등록된 댓글이 없습니다.
