fix(cache): 문서 iframe ?v= 캐시버스터 + SPA 표준 캐시 정책

옛 X-Frame-Options:DENY 응답이 브라우저 캐시에 박혀 서버 수정 후에도 계속
'연결 거부'가 나던 문제의 근본 대응:
- DocViewerPage iframe src에 ?v=2 — 캐시 키를 바꿔 새 응답을 받게(캐시 우회)
- Caddy 캐시 정책 정리: /assets/*(해시파일) 영구 immutable, 그 외 HTML·문서 no-cache
  → 앞으로 헤더/내용 변경이 캐시에 눌어붙지 않고 즉시 반영

검증: 문서=no-cache+SAMEORIGIN, index=no-cache, assets=immutable.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
AWESOMEDEV 2026-07-17 16:38:15 +09:00
parent 91a6c2a9a9
commit 9ae3cf2709
2 changed files with 17 additions and 8 deletions

View File

@ -35,12 +35,17 @@ edu.awesomedevapp.com {
reverse_proxy backend:8080
}
# 학습 문서(HTML)는 캐시에 눌어붙지 않고 서버에 재검증하게 한다.
# 학습 포인트: 예전에 실수로 X-Frame-Options:DENY가 붙은 문서가 브라우저에 캐시되면,
# 서버를 고쳐도 브라우저가 응답을 재사용해 계속 막힌다("연결 거부"). no-cache는
# "쓰기 전에 서버에 물어봐"라 헤더가 바뀌면 바로 반영된다. (문서는 작아서 비용도 작다.)
@docs path /docs/*
header @docs Cache-Control "no-cache"
# ── 캐시 정책 (SPA 표준) ──
# 학습 포인트: 무엇을 오래 캐시하고 무엇을 매번 확인할지 나눈다.
# 1) /assets/* 빌드가 파일명에 해시를 박는다(index-A1B2.js). 내용이 바뀌면 이름이
# 바뀌므로, 파일들은 "영원히" 캐시해도 안전하다(immutable) 빠르다.
# 2) (HTML·학습 문서) 항상 서버에 재검증(no-cache). 그래야 헤더나 내용이 바뀔
# 즉시 반영된다. 예전에 잘못된 보안헤더가 문서 캐시에 눌어붙어 "연결 거부"가 났던
# 문제를 원천 차단한다. (HTML은 작아 재검증 비용도 작다.)
@assets path /assets/*
header @assets Cache-Control "public, max-age=31536000, immutable"
@nocache not path /assets/*
header @nocache Cache-Control "no-cache"
handle {
root * /srv

View File

@ -53,9 +53,13 @@ export default function DocViewerPage() {
{/* : HTML
학습 문서들은 이미 완성된 정적 HTML(public/docs/*.html)이다.
React로 다시 만들 필요 없이 iframe으로 "액자에 넣듯" 보여주면
문서의 자체 스타일도 그대로 살고 CSS와 충돌하지도 않는다. */}
문서의 자체 스타일도 그대로 살고 CSS와 충돌하지도 않는다.
?v= 캐시 버스터: 예전에 잘못된 보안헤더(X-Frame-Options:DENY) 붙은 문서가
브라우저 캐시에 박혀 새로고침으로도 지워지는 문제가 있었다. 주소 뒤에 버전을
붙이면 브라우저가 "다른 파일" 보고 새로 받아온다(캐시 키가 달라짐). 헤더가
바뀌면 숫자만 올리면 된다. */}
<iframe
src={`/docs/${doc.filePath}`}
src={`/docs/${doc.filePath}?v=2`}
title={doc.title}
style={{
width: '100%',