HTTP 캐싱 동작 구성

이 Codelab에서는 Express 제공 프레임워크를 실행하여 Node.js 기반 웹 서버에서 반환한 HTTP 캐싱 헤더를 변경하는 방법을 보여줍니다. 또한 Chrome DevTools의 Network 패널을 사용하여 예상한 캐싱 동작이 실제로 적용되고 있는지 확인하는 방법도 보여줍니다.

샘플 프로젝트 숙지

다음은 샘플 프로젝트에서 작업할 주요 파일입니다.

  • server.js에는 웹 앱의 콘텐츠를 제공하는 Node.js 코드가 포함되어 있습니다. Express를 사용하여 HTTP 요청 및 응답을 처리합니다. 특히 express.static()는 공개 디렉터리에서 모든 로컬 파일을 제공하는 데 사용되므로 serve-static 문서가 유용합니다.
  • public/index.html는 웹 앱의 HTML입니다. 대부분의 HTML 파일과 마찬가지로 URL의 일부로 버전 관리 정보를 포함하지 않습니다.
  • public/app.15261a07.jspublic/style.391484cf.css는 웹 앱의 JavaScript 및 CSS 애셋입니다. 이러한 파일의 각 URL에는 콘텐츠에 해당하는 해시가 포함됩니다. index.html는 로드할 특정 버전의 URL을 추적하는 역할을 합니다.

HTML용 캐싱 헤더 구성

버전 관리 정보가 포함되지 않은 URL 요청에 응답할 때는 응답 메시지에 Cache-Control: no-cache를 추가해야 합니다. 이와 함께 추가 응답 헤더 두 개(Last-Modified 또는 ETag) 중 하나를 설정하는 것이 좋습니다. index.html가 이 카테고리에 속합니다. 이를 두 단계로 나눌 수 있습니다.

첫째, Last-ModifiedETag 헤더는 etaglastModified 구성 옵션에 의해 제어됩니다. 이 두 옵션 모두 실제로 모든 HTTP 응답에 대해 기본적으로 true로 설정되므로, 이 현재 설정에서는 이 동작을 적용하기 위해 선택하지 않아도 됩니다. 그러나 어차피 구성을 명시적일 수 있습니다.

둘째, HTML 문서에만 (이 경우에는 index.html) Cache-Control: no-cache 헤더를 추가할 수 있어야 합니다. 이 헤더를 조건부로 설정하는 가장 쉬운 방법은 맞춤 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의 캐싱 헤더 구성

'지문' 또는 버전 정보가 포함되어 있고 콘텐츠가 변경되지 않는 URL에 대한 요청에 응답할 때는 Cache-Control: max-age=31536000를 응답에 추가합니다. app.15261a07.jsstyle.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 Network 패널이 열려 있는 상태에서 라이브 앱을 미리보기하여 올바른 헤더가 설정되어 있는지 확인할 수 있습니다.

  • 사이트를 미리 보려면 View App을 누른 다음 Fullscreen 전체 화면을 누릅니다.

  • 열 헤더를 마우스 오른쪽 버튼으로 클릭하여 가장 관련성 높은 정보를 포함하도록 Network 패널에 표시되는 열을 맞춤설정합니다.

DevTools의 Network 패널 구성

여기서 주의해야 할 열은 Name, Status, Cache-Control, ETag, Last-Modified입니다.

  • DevTools에서 Network 패널을 연 상태에서 페이지를 새로고침합니다.

페이지가 로드되면 네트워크 패널에 다음과 같은 항목이 표시됩니다.

네트워크 패널 열입니다.

첫 번째 행에는 탐색한 HTML 문서가 표시됩니다. 이는 Cache-Control: no-cache를 통해 적절하게 제공됩니다. 이 요청의 HTTP 응답 상태는 304입니다. 즉, 브라우저가 캐시된 HTML을 즉시 사용하지 않고 대신 Last-ModifiedETag 정보를 사용하여 웹 서버에 HTTP 요청을 전송하여 이미 캐시에 있는 HTML 업데이트가 있는지 확인합니다. HTTP 304 응답은 업데이트된 HTML이 없음을 나타냅니다.

다음 두 행은 버전이 지정된 자바스크립트 및 CSS 애셋입니다. Cache-Control: max-age=31536000와 함께 제공되며 각 HTTP 상태는 200입니다. 사용된 구성으로 인해 Node.js 서버에 수행 중인 실제 요청은 없으며 항목을 클릭하면 '(디스크 캐시에서)' 응답이 수신되었다는 사실을 비롯한 추가 세부정보가 표시됩니다.

200의 네트워크 응답 상태

ETag 및 Last-Modified 열의 실제 값은 그다지 중요하지 않습니다. 중요한 것은 설정되었는지 확인하는 것입니다.

요약

이 Codelab의 단계를 통해 이제 HTTP 캐시를 최적으로 사용하기 위해 Express를 사용하여 Node.js 기반 웹 서버에 HTTP 응답 헤더를 구성하는 방법을 알게 되었습니다. 또한 Chrome DevTools의 Network 패널을 통해 예상 캐싱 동작이 사용되고 있는지 확인하는 단계가 있습니다.