MDN’s new design is in Beta! A sneak peek: https://blog.mozilla.org/opendesign/mdns-new-design-beta/

HTTP caching

현재 번역은 완벽하지 않습니다. 한국어로 문서 번역에 동참해주세요.

웹 사이트와 애플리케이션의 성능은 이전에 가져온 리소스들을 재사용함으로써 현저하게 향상될 수 있습니다. 웹 캐시는 레이턴시와 네트워크 트래픽을 줄여주므로 리소스의 표현에 필요로 하는 시간을 줄여줍니다. HTTP 캐시 사용을 활용하여, 웹 사이트를 좀 더 잘 반응하도록 만들 수 있습니다.

다른 종류의 캐시들

캐싱은 주어진 리소스의 복사본을 저장하고 요청 시에 그것을 서브하는 기술입니다. 웹 캐시가 자신의 저장소 내에 요청된 리소스를 가지고 있다면, 요청을 가로채 원래의 서버로부터 리소스를 다시 다운로드하는 대신 리소스의 복사본을 반환합니다. 이것은 다음과 같은 몇 가지 목표를 달성하게 해줍니다: 모든 클라이언트를 서브할 필요가 없어진 서버의 로드량이 여유로워지며, 클라이언트에 더 가까워지게 되므로 성능이 향상됩니다. 즉, 리소스를 회신하는데 더 적은 비용이 들게 됩니다. 하나의 웹 사이트에 대해, 캐싱은 높은 성능 달성에 중요한 컴포넌트입니다. 반면, 모든 리소스들이 영원히 이상적인 상태에 있는 것이 아니므로 캐싱은 반드시 알맞게 구성되어야 합니다: 리소스가 변경되는 경우에만 캐시해야 한다는 것은 중요한 사항입니다.

캐시에는 몇 가지 종류가 있습니다: 크게 두 가지 부류로 묶을 수 있습니다: 사설 혹은 공유 캐시가 바로 그것입니다. 공유 캐시는 한 명 이상의 사용자에 의한 재사용을 위해 응답을 저장하는 캐시를 말합니다. 이 페이는 거의 대부분 브라우저와 프록시 캐시에 대해서만 다룰 것이나, 그 외에도 더 나은 신뢰도, 성능 그리고 웹 사이트와 웹 애플리케이션의 확장을 위해 웹 서버 위에 배포되는 게이트웨이 캐시, CDN, 리버스 프록시 캐시 그리고 로드 밸랜서 등이 있습니다.

What a cache provide, advantages/disadvantages of shared/private caches.

사설 브라우저 캐시

사설 캐시는 단일 사용자에게 초점이 맞춰져 있습니다. 당신은 이미 당신의 브라우저 설정에서 "caching"을 본적이 있을 겁니다. 브라우저 캐시는 사용자에 의하여 HTTP를 통해 다운로드된 모든 문서들을 가지고 있습니다. 이 캐시는 서버에 대한 추가적인 요청없이 뒤로 가기나 앞으로 가기, 저장, 소스로 보기 등을 위해 이용 가능한 방문했던 문서들을 만드는데 사용됩니다. 더욱이 캐시된 컨텐츠의 오프라인 브라우징을 개선시킵니다.

공유 프록시 캐시

공유 캐시는 한 명 이상의 사용자에 의해 재상용되는 응답을 저장하는 캐시입니다. 예를 들어, 당신의 회사의 ISP는 많은 사용자들을 서브하기 위해 지역 네트워크 기반의 일부분으로써 웹 프록시를 설치해뒀을 수도 있는데, 그 덕분에 조회가 많이 되는 리소스들은 몇 번이고 재사용되어 네트워크 트래픽과 레이턴시를 줄여줍니다.

캐싱 동작의 대상

HTTP 캐싱은 부가적이지만 캐시된 리소스를 재사용하는 것은 보통 바람직한 일입니다. 하지만, 일반적인 HTTP 캐시들은 GET에 대한 응답을 캐싱하는 것으로 제한되며 다른 메서드들은 제외될 겁니다. 일차 캐시 키는 요청 메서드 그리고 대상 URI로 구성됩니다(종종 GET 요청으로만 사용되는 URI만이 캐싱이 대상이 되곤 합니다). 일반적인 캐싱 엔트리의 폼은 다음과 같습니다:

  • 검색 요청의 성공적인 결과: HTML 문서, 이미지 혹은 파일과 같은 리소스를 포함하는 GET 요청에 대한 200 (OK) 응답.
  • 영구적인 리다이렉트: 301 (영구적으로 이동된) 응답.
  • 오류 응답: a 404 (찾을 수 없음) 결과 페이지.
  • 완전하지 않은 결과: 206 (부분적인 컨텐츠) 응답.
  • 캐시 키로 사용하기에 적절한 무언가가 정의된 경우의 GET 이외의 응답.

캐시 엔트리는 요청이 컨텐츠 협상의 대상인 경우, 두번째 키에 의해 구별되는 다중 저장 응답으로 구성되어 있을 겁니다. 좀 더 자세한 내용을 참고하시려면 아래에서 Vary 헤더에 대해서 읽어보시기 바랍니다.

캐싱 제어

Cache-control 헤더

Cache-Control HTTP/1.1 기본 헤더 필드는 요청과 응답 양측 모두에 있어 캐싱 메커니즘을 위한 디렉티브를 지정하는데 사용됩니다. 그것이 제공하는 여러 디렉티브들로 캐싱 정책을 정의하고자 한다면 이 헤더를 사용하시기 바랍니다.

캐시 스토리지 전혀 없음

캐시는 클라이언트 요청 혹은 서버 응답에 관해서 어떤 것도 저장해서는 안됩니다. 요청은 서버 측으로 전송되고 전체 응답은 매번 그리고 항상 다운로드됩니다.

Cache-Control: no-store
Cache-Control: no-cache, no-store, must-revalidate

캐시하지 않음

캐시는 검증을 위해 캐시된 복사본을 하기 방출하기 이전에 원 서버로 요청을 전송하게 될 겁니다.

Cache-Control: no-cache

사설 캐시와 공개 캐시

"공개" 디렉티브는 응답이 어떤 캐시에 의해서든 캐시된다는 것을 가리킵니다. 이것은 HTTP 인증 혹은 보통 캐시 가능하지 않은 응답 상태 코드를 지닌 페이지가 이제 캐시되어야 할 경우 유용할 수 있습니다. 반면, "사설"은 응답이 단일 사용자를 위한 것이며 공유 캐시에 의해 저장되어서는 안된다는 것을 가리킵니다. 사설 브라우저 캐시는 이런 경우에 응답을 저장합니다.

Cache-Control: private
Cache-Control: public

만료

여기서 가장 중요한 디렉티브는 "max-age=<seconds>"로 리소스가 유효하다고 판단되는 최대 시간을 말합니다. Expires와는 다르게, 이 디렉티브는 요청 시간과 관련이 있습니다. 변경되지 않을 애플리케이션 내 파일에 대해, 보통 공격적인 캐싱을 추가할 수 있습니다. 이것은 이미지, CSS 파일 그리고 자바스크립트 파일과 같은 정적 파일들을 포함합니다.

좀 더 자세한 내용을 위해, 아래에서 유효함 섹션을 참고하시기 바랍니다.

Cache-Control: max-age=31536000

검증

"must-revalidate" 디렉티브 사용 시, 캐시는 그것을 사용하기 이전의 오래된 리소스의 상태와 만료된 리소스가 사용되지 않았다는 것을 확실히 해두어야 합니다. 좀 더 자세한 내용은, 아래에서 검증 섹션을 참고하시기 바랍니다.

Cache-Control: must-revalidate

Pragma 헤더

Pragma는 HTTP/1.0 헤더로, HTTP 응답에 대해 특정되지 않으므로, Cache-Control 헤더 필드가 요청 내에서 생략되지 않은 경우, Cache-Control: no-cache와 동일하게 동작할지라도 일반적인 HTTP/1.1 Cache-Control 헤더에 대해 신뢰할 만한 대체 헤더는 아닙니다.  HTTP/1.0 클라이언트와의 하위 호환성을 위한 경우에만 Pragma를 사용하시기 바랍니다.

유효함

리소스가 캐시 내에 저장되고 나면, 이론적으로는 영원히 캐시에 의해 서버될 수도 있습니다. 캐시는 한정적인 캐시를 가지므로 아이템들은 주기적으로 스토리지에서 제거됩니다. 이런 과정을 캐시 축출이라고 부릅니다. 반면, 어떤 리소스들은 서버 상에서 변경될수도 있으므로 캐시가 갱신되어야 합니다. HTTP가 클라이언트-서버 프로토콜이므로, 리소스가 변경됐을 때 서버는 캐시와 클라이언트에 접근할 수 없습니다; 그들은 리소스에 대한 만료 시간을 주고 받아야 합니다. 해당 만료 시간 이전에는, 리소스가 유효합니다; 만료 시간 이후의 리소스는 실효됩니다. 축출 알고리즘은 대게 실효된 리소스 이상의 권한을 유효한 리소스에게 줍니다. 실효된 리소스는 축출되거나 무시되지 않는다는 것을 알아두시기 바랍니다; 캐시가 실효된 리소스에 대한 요청을 받은 경우, 아직 유효한지 아닌지를 검사하기 위해 If-None-Match와 함께 요청을 전송합니다. 만약 그렇다면, 서버는 요청된 리소스 본문을 전송하지 않고 304 (수정되지 않음) 헤더를 돌려보내, 대역폭을 절약합니다.

다음은 이런 과정에 대한 공유 캐시 프록시를 이용한 예제입니다:

Show how a proxy cache acts when a doc is not cache, in the cache and fresh, in the cache and stale.

유효 수명은 몇가지 헤더에 근거해 계산됩니다. "Cache-control: max-age=N" 헤더가 특정된 경우, 유효 수명은 N과 동일합니다. 만약 이 헤더가 없다면, 매우 자주 이런데, Expires 헤더가 있는지 없는지를 검사하게 됩니다. Expires 헤더가 존재한다면, 그것의 값에서 Date 헤더의 값을 뺀 결과가 유효 수명이 됩니다. 마지막으로, 그 헤더도 없다면, Last-Modified 헫더를 찾게 됩니다. 이 헤더가 있다면, 캐시의 유효 수명은 Date 헤더 값에서 Last-modified 헤더 값을 뺀 값을 10으로 나눈 결과가 됩니다.
만료 시간은 다음과 같이 계산됩니다:

expirationTime = responseTime + freshnessLifetime - currentAge

responseTime는 브라우저가 수신한 시간을 말합니다.

활성화된(Revved) 리소스

우리가 캐시된 리소스를 사용하면 사용할 수록, 웹 사이트의 응답성과 성능은 점점 더 좋아질 것입니다. 이것을 최적화하기 위한 실제 방법은 만료 시간을 가능한 더 먼 미래로 설정하는 것입니다. 이것은 리소스를 정기적으로 혹은 자주 갱신함으로써 가능하지만, 아무 드물게 업데이트되는 리소스의 경우에는 이게 문제가 됩니다. 이런 리소스들은 캐시한 리소스로부터 최대한 활용되는 리소스들로, 앞서 얘기한 방법 덕분에 이러한 리소스들을 갱신하기 더 어렵게 됩니다. 이것은 각 웹 페이지에 포함되고 링크된 기술적인 리소스들을 대표합니다: 자바스크립트와 CSS 파일들의 변경은 드물지만, 그들이 변경될 때 빠르게 갱신되기를 원할 겁니다.

웹 개발자들은 Steve Sounders가 revving[1]이라고 부렀던 기술을 발명했습니다. 드물게 업데이트되는 파일들은 명확한 방법으로 이름지어 집니다: 보통은 파일 이름인, 파일들의 URL에 수정(혹은 버전) 번호가 추가됩니다. 그와 같이 해당 리소스의 각각의 새로운 수정본은 결코 변경되지 않으며 보통은 1년 혹은 그 이상의 아주 먼 미래에 만료될 수 있는 그 자체로 리소스로써 간주됩니다. 새로운 버전들을 가지기 위해, 해당 리소스들과의 모든 연결은 모두 변경되어야 하며, 그것이 이 방법의 단점입니다: 이것은 보통 웹 개발자들이 사용하는 툴체인에 의해 다루어지는 추가적인 복잡함입니다. 드물게 변경되는 리소스들이 변경되는 경우 자주 변경되는 리소스에 추가적인 변화를 초래합니다. 이런 리소스들이 읽혀지는 경우, 다른 리소스들의 새로운 버전들도 읽혀지게 됩니다.

이 기술은 추가적인 이점도 가지고 있습니다: 동시에 캐시된 두 개의 리소스를 갱신하는 것은 한 리소스의 기한이 지난 버전이 다른 리소스의 새로운 버전과 함께 혼합되어 사용되는 경우를 초래할 것입니다. 이것은 웹 사이트가 상호 간의 의존성을 가지고 있는 CSS 스타일시트와 자바스크립트를 가지고 있는 경우(같은 HTML 요소를 참조하기에 서로 의존하게 됩니다) 매우 중요합니다.

활성화된(revved) 리소스에 추가된 수정 버전은 1.1.3과 같은 클래식한 수정 문자열 혹은 단조롭게 증가되는 숫자 묶음이 될 필요가 없습니다. 그것은 해시 혹은 날짜와 같이 충돌만 되지 않는다면 무엇이든지 될 수 있습니다.

캐시 검증

재검증은 사용자가 리로드 버튼을 누를 경우 촉발됩니다. 재검증은 캐시된 응답이 "Cache-control: must-revalidate" 헤더를 포함하고 있는 경우 일반적인 브라우징 상태에서 촉발되기도 합니다. 또 다른 요인은 Advanced->Cache 환경설정 패널 내에 캐시 검증 환경 설정입니다. 거기에는 문서가 로드될 때마다 검증을 강제할 수 있는 옵션이 있습니다.

캐시된 문서의 만료 시간이 가까워져오면, 문서가 검증되거나 다시 불러오게 됩니다. 검증은 서버가 강한 검증 혹은 약한 검증 중 하나라도 제공하는 경우에만 일어날 수 있습니다.

ETags

ETag 응답 헤더는 강한 검증으로써 사용될 수 있는 사용자 에이전트에게 있어 불분명한 값입니다. 그것은 브라우저와 같은 HTTP 사용자 에이전트가 이 문자열이 무엇을 표현하는지 알 수 없고 그것의 값이 무엇이 될지를 예측할 수 없다는 것을 의미합니다. ETag 헤더가 리소스에 대한 응답의 일부라면, 클라이언트는 이후 요청의 해더 내에 (캐시된 응답을 검증하기 위해) If-None-Match 헤더를 발급할 수 있습니다.

Last-Modified 응답 헤더는 약한 검증으로써 사용될 수 있습니다. 그것이 1초의 해상도만 가질 수 있기에 약하다고 간주됩니다. Last-Modified 헤더가 응답 내에 나타나면, 클라이언트는 캐시된 문서를 검증하기 위해 If-Modified-Since 요청 헤더를 발급할 수 있습니다.

검증 요청이 이루어지면, 서버는 검증 요청을 일반적인 200 OK으로 요청과 응답을 무시하거나 브라우저에게 캐시된 복사본을 사용하도록 지시하기 위해 304 Not Modified (본문을 비워둔 상태로)를 반환할 수 있습니다. 후자의 응답은 캐시된 문서의 만료 시간을 갱신하는 헤더를 포함할 수도 있습니다.

상황에 따른 응답

Vary HTTP 응답 헤더는 원 서버로부터 신선한 리소스를 요청하지 않고 캐시된 응답이 사용될 수 있는지를 결정하기 위해 이후의 요청 헤더를 일치시키는 방식을 결정합니다.

캐시가 Vary 헤더 필드를 지닌 캐시된 응답에 의해 만족될 수 있는 요청을 수신한 경우, Vary 헤더에 의해 지명된 모든 헤더 필드들이 원래의 (캐시된) 요청과 새로운 요청 모두와 일치하지 않는다면 그 캐시된 응답을 사용해서는 안 됩니다.

The Vary header leads cache to use more HTTP headers as key for the cache.

예를 들자면, 이것은 컨텐츠를 동적으로 서브하는 경우에 유용할 수 있습니다. Vary: User-Agent 헤더가 사용되는 경우, 캐싱 서버는 캐시로부터 페페이지를 서브해야 할지를 결정할 때 사용자 에이전트를 고려해야만 합니다. 만약 당신이 모바일 사용자에게 다른 컨텐츠를 서브하고 있다면, 그 헤더는 캐시가 모바일 사용자에게 사이트의 데스크톱 버전을 실수로 서브하는 일을 피하도록 도와줄 것입니다. 추가로, 구글과 다른 검색 엔진들이 페이지의 모바일 버전을 찾는데 도움을 줄 수 있으며, 그들에게 클로킹이 의도되지 않았다는 것을 알려줍니다.

Vary: User-Agent

User-Agent 헤더 값은 모바일과 데스크톱 클라이언트에 따라 다르므로("다양하므로"), 캐시는 모바일 컨텐츠를 데스크톱 사용자에게 혹은 그 반대의 경우라도 실수로 서브하지는 않을 겁니다.

함께 참고할 내용

문서 태그 및 공헌자

 이 페이지의 공헌자: devcken
 최종 변경: devcken,