[HTTP] 캐시
카테고리: HTTP
태그: HTTP
👣 사본을 신선하게 유지하기.
캐시된 데이터와 원서버의 데이터는 항상 일치하도록 관리되어야 한다. HTTP에서 매달, 매초 변경되는 데이터를 신선하게 유지할 수 있는 방법을 배워본다.
1.1 문서 만료
- HTTP는
Cache-Control과Expires라는 특별한 헤더들을 이용해서 원 서버가 각 문서에 유효기간을 붙일 수 있게 한다.
1.2 유효기간과 나이
- 서버는 응답 본문과 함께 HTTP/1.0+ Expires나 HTTP/1.1 Cache-Control: max-age 응답 헤더를 이용해서 유효기간을 명시한다.
| 헤더 | 설명 | 예시 |
|---|---|---|
Cache-Control: max-age |
max-age 값은 더 이상 신선하지 않다고 간주될 때까지의 최댓값(초 단위)이다. | Cache-Control: max-age=484200 |
Expires |
절대 유효기간을 명시한다. 유효 기간이 지났다면, 그 문서는 더 이상 신선하지 않다고 간주된다. | Expires: Fri, 05 Jul 2002, 05:00:00 GMT |
1.3 서버 재검사
캐시된 문서가 만료되었다는 것은, 캐시에 저장된 그 문서가 원 서버에 현재 존재하는 것과 다르다는 것을 의미하지는 않는다. 다만 이제 재검사할 시간이 되었음을 뜻한다.
- 재검사 결과 콘텐츠가 변경되었다면, 캐시는 그 문서의 새로운 사본을 가져와 오래된 데이터 대신 저장한 뒤 클라이언트에게도 보내준다.
- 재검사 결과 콘텐츠가 변경되지 않았다면, 캐시는 새 만료일을 포함한 새 해더들만 가져와서 캐시 안의 헤더들을 갱신한다.
1.4 조건부 메서드와의 재검사
- HTTP는 캐시가 서버에게 ‘조건부 GET’ 요청을 함으로써 신선도 검사와 객체를 받아올 수 있다.
- 조건부 GET은 GET 요청 메시지에 특별한 조건부 헤더를 추가함으로써 시작된다. 웹 서버는 조건이 참인 경우 객체를 반환한다.
- HTTP는 5가지의 조건부 요청 헤더를 정의한다. 그 중 If-Modified-Since와 If-None-Match에 대해 알아본다.
| 헤더 | 설명 |
|---|---|
If-Modified-Since: <date> |
캐시가 캐시된 문서를 재검사 하려고 할 떄, 캐시된 사본이 마지막으로 수정된 날짜가 담긴 If-Modified-Since 헤더를 포함한다. 만약 문서가 주어진 날짜 이후로 수정되었다면 객체를 반환한다. 이때 Last-Modified 응답 헤더와 함께 사용된다. |
If-None-Match: <tags> |
마지막 변경된 날짜를 비교해보는 대신, 서버는 문서에 대한 일련번호와 같이 동작하는 특별한 태그(ETag)를 제공할 수 있다. If-None-Match 헤더는 캐시된 태그가 서버에 있는 문서의 태그와 다른 경우 객체를 반환한다. |
1.5 If-Modified-Since: 날짜 재검사
- 만약 문서가 주어진 날짜 이후에 변경되었다면, If-Modified-Since(IMS) 조건은 참이고, 따라서 GET 요청은 200 OK로 응답한다. 서버는 새로운 만료 날짜와 그 외 다른 정보들이 담긴 헤더들과 함께 캐시에게 반환된다.
- 만약 문서가 주어진 날짜 이후에 변경되지 않았다면 조건은 거짓이고, 서버는 작은 304 Not Modified 응답 메시지를 돌려준다. 효율을 위해 본문은 보내지 않는다. 응답은 헤더들을 포함하는데 갱신이 필요한 것들만 보내준다. 예를 들어, Content-type 헤더는 잘 변하지 않기 때문에 대게 보내줄 필요가 없고, 새 만료 날짜는 보통 보내주게 된다.
- If-Modified-Since 헤더는 서버 응답 헤더의 Last-Modified 헤더와 함께 동작한다. 원 서버는 제공하는 문서에 최근 변경 일시를 붙인다.
1.6 If-None-Match: 엔터티 태그 재검사
다음과 같은 상황에서는 If-Modified-Since 재검사가 적절히 행해지기 어려울 수 있다.
- 어떤 문서는 일정 시간 간격으로 다시 쓰여지지만 실제로는 같은 데이터를 포함하고 있다. 내용에는 아무런 변화가 없지만 변견시각은 변화할 수 있다.
- 1초보다 작은 간격으로 갱신되는 문서를 제공하는 서버들에게는, 변경일에 대한 1초의 정밀도는 충분하지 않을 수 있다.
이런 경우 If-Modified-Since 대신 If-None-Match를 사용할 수 있다. If-None-Match는 다음과 같이 동작한다.
- 캐시에서 엔터티 태그 “v2.6”인 어떤 문서를 갖고 있다.
- 캐시는 원서버에게 태그가 더 이상 “v2.6”이 아닌 경우에만 새 객체를 달라고 If-None-Match 헤더와 함께 요청한다.
- 만약 태그가 여전히 변경되지 않았다면 서버는 304 Not Modified 응답을 반환한다.
- 만약 태그가 변경되었다면, 서버는 200 OK 응답으로 새 문서를 새 ETag와 함께 반환한다.
1.7 언제 엔터티 태그를 사용하고 언제 Last-Modified를 사용할까?
- HTTP/1.1 클라이언트는 만약 서버가 엔터티 태그를 반환했다면, 반드시 ETag 검사기를 사용해야 한다.
- 만약 서버가 Last-Modified 값만을 반환했다면, 클라이언트는 If-Modified-Since 검사를 사용할 수 있다.
- 만약 ETag와 If-Modified-Since 모두 사용 가능하다면, HTTP/1.0과 HTTP/1.1 캐시 모두 적절히 응답할 수 있도록 클라이언트는 각각을 위해 두 가지의 재검사 정책을 모두 사용해야 한다.
⌨️ 캐시 제어
HTTP는 문서가 만료되기 전까지 얼마나 오랫동안 캐시될 수 있게 할 것인지 서버가 설정할 수 있는 여러 가지 방법을 정의한다. 우선순위대로 나열해보면 서버는,
- Cache-Control: no-store 헤더를 응답에 첨부할 수 있다.
- Cache-Control: no-chace 헤더를 응답에 첨부할 수 있다.
- Cache-Control: must-revalidate 헤더를 응답에 첨부할 수 있다.
- Cache-Control: max-age 헤더를 응답에 첨부할 수 있다.
- Expires 날짜 헤더를 응답에 첨부할 수 있다.
2.1 no-cache와 no-store 응답 헤더
Cache-Control: no-store
Cache-Control: no-cache
Pragma: no-cache
'no-store'가 표시된 응답은 캐시가 그 응답의 사본을 만드는 것을 금지한다. 캐시는 클라이언트에게no-store응답을 전달하고 나면 객체를 삭제한다.'no-cache'로 표시된 응답은 로컬 캐시 저장소에 저장될 수 있지만, 먼저 서버와 재검사 하지 않고서는 캐시에서 클라이언트에게 제공될 수 없다.'Pragma: no-cache'헤더는 HTTP/1.0+와의 하위호환성을 위해 HTTP/1.1에 포함되어 있다.
2.2 Must-Revalidate 응답 헤더
- Cache-Control: must-revalidate 응답 헤더는 서버와의 최초의 재검사 없이는 제공해서는 안됨을 의미한다.
- 일반적으로 max-age와 함께 사용되며, max-age: 10 응답 헤더와 함께 사용될 경우 최초 검증 이후 10초 동안 재검사 없이 캐시된 데이터를 사용할 수 있음을 의미한다.
2.2.1 no-cache와 Must-Revalidate 차이
- Cache-Control: no-cache 와 차이점은 재검사의 주기에서 차이가 있다.
no-cache의 경우 매 요청마다 재검사가 필요하다. - 만약 서버가 재검사를 시도했을 떄 원 서버가 사용할 수 없는 상태라면, 캐시는 반드시 504 Gateway Timeout error를 반환해야 한다.
no-cache의 경우 이전 데이터라도 보여주기 위해 200 OK로 응답할 수 있다.
2.3 클라이언트 요청 헤더
- 웹 브라우저는 브라우저나 프락시 캐시에서 신선하지 않은 콘텐츠를 강제로 갱신시켜 주는 리프레시 리로드 버튼을 갖고 있다.
- 이 리프레시 버튼은 Cache-Control 요청 헤더가 추가된 GET 요청을 발생시켜서, 강제로 재검사하거나 서버로부터 콘텐츠를 무조건 가져온다.
- 클라이언트는 Cache-Control 요청 헤더를 사용하여 만료 제약을 엄격하게 하거나 느슨하게 할 수 있다.
| 헤더 | 설명 |
|---|---|
Cache-Control: max-stale Cache-Control: max-stale = <s> |
캐시는 신선하지 않은 문서라도 자유롭게 제공할 수 있다. 만약 s 매개변수가 지정되면, 클라이언트는 만료시간이 s초 만큼 지난 문서도 받아들인다. |
Cache-Control: min-fresh = <s> |
클라이언트는 지금으로부터 적어도 s초 만큼은 신선한 문서만 받아들인다. |
Cache-Control: max-age = <s> |
캐시는 s초 보다 오랫동안 캐시된 문서를 반환할 수 없다. |
Cache-Control: no-cachePragma: no-cahce |
이 클라이언트는 캐시된 리소스를 재검사하기 전에는 받아들이지 않을 것이다. |
Cache-Control: no-store |
이 캐시는 저장소에서 최대한 빨리 삭제해야 한다. |
Cache-Control: only-if-cached |
클라이언트는 캐시에 있는 사본만을 원한다. |
👍 개인 공부 기록용 블로그입니다. 오류나 조언이 있으시면 언제든지 댓글 혹은 메일로 남겨주시면 감사하겠습니다! 😄
댓글남기기