이 Codelab에서는 Express 서비스 프레임워크를 실행하는 Node.js 기반 웹 서버에서 반환되는 HTTP 캐싱 헤더를 변경하는 방법을 보여줍니다. 또한 Chrome DevTools의 네트워크 패널을 사용하여 예상한 캐싱 동작이 실제로 적용되는지 확인하는 방법도 보여줍니다.
샘플 프로젝트 숙지하기
샘플 프로젝트에서 작업할 주요 파일은 다음과 같습니다.
server.js
에는 웹 앱의 콘텐츠를 제공하는 Node.js 코드가 포함되어 있습니다. Express를 사용하여 HTTP 요청과 응답을 처리합니다. 특히express.static()
는 공개 디렉터리의 모든 로컬 파일을 제공하는 데 사용되므로serve-static
문서가 유용합니다.public/index.html
는 웹 앱의 HTML입니다. 대부분의 HTML 파일과 마찬가지로 URL에 버전 관리 정보가 포함되어 있지 않습니다.public/app.15261a07.js
및public/style.391484cf.css
은 웹 앱의 JavaScript 및 CSS 애셋입니다. 이러한 파일에는 콘텐츠에 해당하는 해시가 URL에 포함되어 있습니다.index.html
는 로드할 특정 버전이 지정된 URL을 추적하는 역할을 합니다.
HTML의 캐싱 헤더 구성
버전 관리 정보가 포함되지 않은 URL 요청에 응답할 때는 응답 메시지에 Cache-Control: no-cache
을 추가해야 합니다. 이와 함께 Last-Modified
또는 ETag
의 두 가지 추가 응답 헤더 중 하나를 설정하는 것이 좋습니다. index.html
가 이 카테고리에 속합니다. 이 작업은 두 단계로 나눌 수 있습니다.
먼저 Last-Modified
및 ETag
헤더는 etag
및 lastModified
구성 옵션으로 제어됩니다. 이 두 옵션은 실제로 모든 HTTP 응답에 대해 true
로 기본 설정되므로 현재 설정에서는 이 동작을 얻기 위해 선택하지 않아도 됩니다. 하지만 구성에서 명시적으로 지정할 수 있습니다.
두 번째로 Cache-Control: no-cache
헤더를 추가할 수 있어야 하지만 HTML 문서 (이 경우 index.html
)에만 추가해야 합니다. 이 헤더를 조건부로 설정하는 가장 쉬운 방법은 맞춤 setHeaders function
를 작성하고 그 안에서 수신 요청이 HTML 문서에 대한 요청인지 확인하는 것입니다.
- 리믹스하여 수정을 클릭하여 프로젝트를 수정할 수 있도록 합니다.
server.js
의 정적 제공 구성은 다음과 같이 시작됩니다.
app.use(express.static('public'));
- 위에 설명된 대로 변경하면 다음과 같은 결과가 표시됩니다.
app.use(express.static('public', {
etag: true, // Just being explicit about the default.
lastModified: true, // Just being explicit about the default.
setHeaders: (res, path) => {
if (path.endsWith('.html')) {
// All of the project's HTML files end in .html
res.setHeader('Cache-Control', 'no-cache');
}
},
}));
버전이 지정된 URL의 캐싱 헤더 구성
'fingerprint' 또는 버전 관리 정보가 포함되어 있고 콘텐츠가 변경되지 않는 URL 요청에 응답할 때는 Cache-Control: max-age=31536000
를 응답에 추가하세요. app.15261a07.js
및 style.391484cf.css
이 이 카테고리에 속합니다.
이전 단계에서 사용한 setHeaders function
를 기반으로 지정된 요청이 버전이 지정된 URL에 대한 요청인지 확인하는 추가 로직을 추가하고, 그렇다면 Cache-Control:
max-age=31536000
헤더를 추가할 수 있습니다.
가장 강력한 방법은 정규식을 사용하여 요청된 애셋이 해시가 속하는 것으로 알려진 특정 패턴과 일치하는지 확인하는 것입니다. 이 샘플 프로젝트의 경우 항상 숫자 0~9와 소문자 a~f (즉, 16진수 문자)로 구성된 8자입니다. 해시는 항상 양쪽에서 .
문자로 구분됩니다.
이러한 일반 규칙과 일치하는 정규 표현식은 new RegExp('\\.[0-9a-f]{8}\\.')
로 표현할 수 있습니다.
setHeaders
함수를 다음과 같이 수정합니다.
app.use(express.static('public', {
etag: true, // Just being explicit about the default.
lastModified: true, // Just being explicit about the default.
setHeaders: (res, path) => {
const hashRegExp = new RegExp('\\.[0-9a-f]{8}\\.');
if (path.endsWith('.html')) {
// All of the project's HTML files end in .html
res.setHeader('Cache-Control', 'no-cache');
} else if (hashRegExp.test(path)) {
// If the RegExp matched, then we have a versioned URL.
res.setHeader('Cache-Control', 'max-age=31536000');
}
},
}));
DevTools를 사용하여 새 동작 확인
정적 파일 서버가 수정되었으므로 DevTools 네트워크 패널을 열고 라이브 앱을 미리 보면서 올바른 헤더가 설정되었는지 확인할 수 있습니다.
- 열 헤더를 마우스 오른쪽 버튼으로 클릭하여 네트워크 패널에 표시되는 열을 맞춤설정하여 가장 관련성 높은 정보를 포함하세요.
여기서 주의해야 할 열은 Name
, Status
, Cache-Control
, ETag
, Last-Modified
입니다.
- DevTools가 네트워크 패널에 열린 상태에서 페이지를 새로고침합니다.
페이지가 로드되면 네트워크 패널에 다음과 같은 항목이 표시됩니다.
첫 번째 행은 탐색한 HTML 문서입니다. 이 파일은 Cache-Control: no-cache
로 올바르게 제공됩니다. 해당 요청의 HTTP 응답 상태는 304
입니다. 즉, 브라우저가 캐시된 HTML을 즉시 사용하지 않고 대신 Last-Modified
및 ETag
정보를 사용하여 웹 서버에 HTTP 요청을 보내 캐시에 이미 있는 HTML이 업데이트되었는지 확인했습니다. HTTP 304 응답은 업데이트된 HTML이 없음을 나타냅니다.
다음 두 행은 버전이 지정된 JavaScript 및 CSS 애셋용입니다. Cache-Control: max-age=31536000
로 제공되며 각 항목의 HTTP 상태는 200
입니다.
사용된 구성으로 인해 Node.js 서버에 실제 요청이 이루어지지 않으며 항목을 클릭하면 응답이 '(디스크 캐시에서)' 왔다는 것을 비롯한 추가 세부정보가 표시됩니다.
ETag 및 Last-Modified 열의 실제 값은 중요하지 않습니다. 중요한 것은 설정되었는지 확인하는 것입니다.
요약
이 Codelab의 단계를 완료했으므로 이제 Express를 사용하여 Node.js 기반 웹 서버에서 HTTP 응답 헤더를 구성하여 HTTP 캐시를 최적으로 사용하는 방법을 잘 알게 되었습니다. Chrome DevTools의 네트워크 패널을 통해 예상되는 캐싱 동작이 사용되고 있는지 확인하는 단계도 있습니다.