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인지 확인하고, 버전 관리 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 네트워크 패널을 열고 실시간 앱을 미리 보고 올바른 헤더가 설정되었는지 확인할 수 있습니다.

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

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

DevTools의 네트워크 패널을 구성합니다.

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

  • DevTools가 Network 패널로 열려 있는 상태에서 페이지를 새로고침합니다.

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

네트워크 패널 열

첫 번째 행은 이동한 HTML 문서에 관한 것입니다. Cache-Control: no-cache를 사용하여 올바르게 제공됩니다. 이 요청의 HTTP 응답 상태는 304입니다. 즉, 브라우저는 캐시된 HTML을 즉시 사용하지 않아야 한다는 것을 알고 있었지만 대신 Last-ModifiedETag 정보를 사용하여 웹 서버에 HTTP 요청을 보내 캐시된 HTML에 업데이트가 있는지 확인했습니다. HTTP 304 응답은 업데이트된 HTML이 없음을 나타냅니다.

다음 두 행은 버전이 지정된 JavaScript 및 CSS 애셋용입니다. Cache-Control: max-age=31536000로 제공되는 것을 볼 수 있으며 각 항목의 HTTP 상태는 200입니다. 사용된 구성으로 인해 Node.js 서버에 실제 요청이 전송되지 않으며 항목을 클릭하면 응답이 '(디스크 캐시에서)' 전송되었다는 등의 추가 세부정보가 표시됩니다.

네트워크 응답 상태 200입니다.

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

요약

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