작성자 : joanne*
* 1 Cache의 개념
+ 1.1.1 HTTP Cache란?
* 2 HTTP1.1의 cache field
+ 2.1.1 Request header
# 2.1.1.1 Request header의 general-header 중 cache 관련 항목
# 2.1.1.2 Request header의 request header 중 cache 관련 항목
+ 2.1.2 Response header
# 2.1.2.1 Response header의 general-header 중 cache 관련 항목
# 2.1.2.2 Response header의 Entity-Header 중 cache 관련 항목
# 2.1.2.3 Response header의 Vary Header
* 3 Cache의 동작 방식
o 3.1 Expiration & Validation
+ 3.1.1 Expiration
# 3.1.1.1 Expiration의 계산
* 3.1.1.1.1 current_age의 계산
+ 3.1.2 Validation
# 3.1.2.1 E-tag, Last-Modified를 사용할 때의 규칙
* 4 사례
+ 4.1.1 nocache
+ 4.1.2 Etag, max-age
+ 4.1.3 Expires
# 4.1.3.1 Vary와 Accept-Encoding
Cache의 개념
HTTP Cache란?
- 브라우져가 웹 페이지 구성요소를 PC의 hard disk에 저장했다가 같은 요소가 다시 불릴 때 서버에 요청하지 않고 저장된 것을 보여주는 것
- cache는 client와 svr 사이에 위치하여 기능을 수행함으로써 데이터의 전송을 줄여 양측의 부하를 줄이고, 보다 빨리 리소스를 얻을 수 있도록 한다.
HTTP1.1의 cache field
Request header
Request-Line
headers : general-header, request-header, Entity-Header, ...
CRLF
message-body
Request header의 general-header 중 cache 관련 항목
- General-header 안에 Cache Control이라는 지시자로 cache의 제어가 가능하다.
Cahce-Control :
cache-request-directive=
"no-cache" 캐시 하지 않는다.
"no-store" 신속히 넘긴 후에 정보를 제거한다.
"max-age = seconds" seconds에 지정한 것보다 오래된 entry는 캐시하지 않는다.
"max-stale [=seconds]" 만료된 데이터를 보낸다. 만약 seconds가 지정되어 있다면 지정한 숫자보다 적은 만료된 데이터를 보낸다.
"min-fresh [=seconds]" 명시된 seconds의 수 이후의 변경된 새 데이터만 보낸다.
"only-if-cached" 새로운 데이터를 검색하지 않고 캐시에 있는 데이터만 반환한다.
Request header의 request header 중 cache 관련 항목
"If-Match" 이미 이전에 캐시되었던 entity는 연관된 entity tag(이하 E-tag)를 포함하여 이 entity과 현재의 것임을 증명할 수 있다.
사용형식 - If-Match: E-tag
"If-None-Match" 조건적으로 요청하는 것으로 주어진 엔티티 태그와 어떠한 것도 매치되지 않아야 요청 계속
Response header
Status-Line
headers : general-header, request-header, Entity-Header, ...
CRLF
message-body
Response header의 general-header 중 cache 관련 항목
- General-header 안에 Cache Control이라는 지시자로 cache의 제어가 가능하다.
Cahce-Control :
cache-response-directive=
"public" 어떠한 캐쉬라도 캐싱할 수 있다.
"private" 공유된 캐쉬는 캐시하지 않는다.
"no-cache" 캐쉬하지 않는다.
"no-transform" 데이터를 변환하지 않는다.
"must-revalidate" 클라이언트는 데이터를 재확인 해야 한다.
"proxy-revalidate" 개인적인 클라이언트 캐시를 제외하고 데이터를 재확인 해야한다.
"max-age"="delta-seconds" 문서는 지정된 seconds만큼 변화가 없는 상태라고 생각
Response header의 Entity-Header 중 cache 관련 항목
"E-tag" Data 고유의 entity tag. INode, MTime, Size값을 나타내는 것으로 파일의 갱신 여부를 확인하기 위해 사용된다.
"Last-Modified" : Tue, 15 Nov 1994 12:45:26 GMT 의 형식으로 사용되며 origin svr에서의 최종 수정시간을 뜻한다.
웹 페이지 전송시간을 기록해 뒀다가 Last-Modified이 값과 비교한 다음 페이지가 수정되었을 때만 Data를 가져가도록 작동한다.
"Expires" date의 형식으로 문서가 변경될 수도 있을 때의 시간 또는 그것의 정보가 유효하지 않을 때의 시간을명시한다.
그 시간 이후, 문서는 변경 또는 삭제되거나 그렇지 않을 수 있다.
Response header의 Vary Header
- Vary : 캐시된 entity가 다중 자원을 가지고 있으므로 요청한 헤더를 지정한 목록이 상황에 따라 변할 수 있다는 것을 지정한다. 여러 개의 헤더는 세미콜론으로 구분하여 나열한다.Vary 헤더를 포함하여 캐시가 해당 자원에 대한 향후 요구를 적절하게 해석할 수 있도록 한다.
- Accept-encoding : Request header의 Accept-encoding은 compress 또는 gzip과 같은 클라이언트가 받아들일 수 있는 인코딩 방식을 지정한다. 여러 개의 인코딩 방식을 쉼표로 구분하여 나열한다. 만약 인코딩 형태를 지정하지 않으면 어떤 형태도 클라이언트에게 받아들여지지 않는다.
- Accept-encoding: gzip 가 수신되는 경우 미리 압축된 내용을 서비스하도록 구성된 디렉토리의 파일에 대한 모든 요청이 해당 디렉토리의 상응하는 압축 파일에 대한 요청으로 리다이렉션됩니다(해당 파일이 존재하는 경우).웹 서버가 myfile.html에 대한 요청을 수신하고 myfile.html 및 myfile.html.gz가 모두 존재하는 경우 적절한 Accept-encoding 헤더를 가진 이러한 요청에서 압축된 파일을 수신하게 된다.
- Vary : 서버는 자신이 캐쉬한 응답을 적절한 Accept-Encoding 요청 헤더를 보낸 클라이언트에게만 보내도록 Vary: Accept-Encoding으로 설정할 수 있다.
Cache의 동작 방식
Expiration & Validation
HTTP/1.1의 캐시의 목적은 response, request의 round-trip을 줄이고, 또 full response의 발송을 줄여 대역폭을 절약하는 것이다. 이를 위해 expiration, validation 두 가지 방법을 사용한다.
- Expiration : response-request의 roundtrip 줄이기 위해 expiration(만기일)방식을 사용한다.
- Validation : full response의 발송을 줄여 network bandwith를 절약한다.
Expiration
- http 캐시는 origin SVR로 request를 보내고, response를 받는 round-trip 과정을 최소화할 때 최상으로 작동한다
- roundtrip 과정을 최소화하기 위해 User-Agent(브라우져)가 웹 문서를 요구할 때 캐시에 저장되어있는 만기일 을 확인하여 만기일이 지나지 않았을 경우에 캐시된 문서를 브라우져로 응답하는 매커니즘을 사용한다.
- 서버는 Expires header 또는 Cache-Control header의 max-age 지시자를 사용하여 만기일을 선정한다.
- Expires header나 Cache-Control header에 지정값이 없으면 heuristic Expiration을 사용한다.
- Expires Header
헤당 오브젝트가 얼마동안 유효한지를 표시해주는 항목
Expiration의 계산
- 서버는 Expires header 또는 Cache-Control header의 max-age 지시자를 사용하여 만기일을 선정한다.
expires_value : expires 헤더 값을 표시
max_age_value : cache control 헤더에 max-age 지시자가 가지고 있는 값
- 만기일을 선정하는 과정은 Expires header보다 Max Age가 우선이다. 즉 Expires header가 설정되어 있어도 Max Age가 설정되어있다면 그 값이 우선이 된다.
- 만기일에대한 별다른 설정이 없다면 heuristic expiration time(자동설정 만기시간)을 할당한다.
- Data가 만기일을 지나지 않았다면 이 자료는 fresh하다고 표현한다. 이 때, fresh한 지의 여부는 다음과 같은 방법으로 결정된다.
freshness_lifetime = max_age_value
freshness_lifetime = expires_value - date_value
response is fresh = ( freshness_lifetime > current_age)
current_age의 계산
- fresh 여부를 판단할 때 사용되는 current_age는 다음과같이 계산된다.
- date_value(Date head) : 응답이 생성된 시간
- age_value : 캐쉬 잔류시간 + 네트워크 이동시간
- corrected_received_age = max(now-date_value, age_value)
- request_time : 요청이 생성된 시간
- response_time : 캐쉬가 응답을 받은 시간
- now : 현재 시간
- corrected_initial_age = connected_received_age + (now - request_time)
- apparent_age = max(0, response_time - date_value)
- corrected_received_age = max(apparent_age, age_value)
- response_dalya = response_time - request time
- corrected initial age = corrected_received_age + response_delay
- resident_time = now - response time
- current_age = corrected_initial_age + resident_time
Validation
- http SVR는 캐시된 엔트리를 아직도 사용할 수 있는지 알아보는 Validation 작업을 수행한다.
- full response를 주고 받는 것은 BW overhead가 크고, 이런 overhead를 줄이기 위해 Cache Validator를 사용한다.
- Cache Validator를 비교하여 변화가 없는 경우는 304(Not Modified), 변화가 있을 경우 200(OK)를 리턴하고 문서를 전송한다.
- Cache Validator로 E-tag와 Last-modified header가 사용된다.
- E-tag의 값이 Last-Modifed 값보다 우선적으로 Validating된다.
E-tag, Last-Modified를 사용할 때의 규칙
- HTTP/1.1 origin sever:
새로운 것을 생성하는 것이 불가능하지 않는 한 E-tag validator를 발송해야 함.
성능에 대해 고려했을 때 weak E-tag를 사용해도 될 때 또는 E-tag를 발송하는 것이 효과적이지 못할 때 강한 엔터티 태그 대신 weak entity 태그를 발송할 수도 있음.
(달리 표현하면 HTTP/1.1 원서버의 바람직한 행태는 Stroing E-tag와 Last-Modified 값 모두를 발송해야함)
- HTTP/1.1 client:
서버가 E-tag를 제공하였으면 클라이언트는 If-Match 또는 If-None-Match를 사용하여 그 E-tag를 반드시 사용해야 함.strong entity : 검증자가 동일한 entity인지를 검증하는 과정에서 entity가 어떤 식으로든 변경이 되었다면 그에 해당하는 validator도 변경되었을 것이다. 이런 경우 validator를 strong validator라고 부른다.
weak entity : entity의 변화가 상대적으로 중요한 의미를 갖지 않는다면 validator를 일일이 변경하지 않는 경우가 있을 수 있다. 이런 validator는 weak 태그를 붙여 weak validator로 설정 가능하다.
사례
nocache
- ctrl+F5로 새로고침 했을 때 Cache-Control : no-cache(캐쉬하지 않음)가 설정이 되는 것을 알 수 있다.
Etag, max-age
- 동일 파일에 대해 새로고침 했을 때 response로 304(not-modified)status를 받았다.
- Validation을 위해 요청 해더에 If-None-Match값이 삽입되었고, 응답헤더의 Etag값과 동일함을 알 수 있다.
- Etag값으로 파일이 동일함을 확인하였고, 캐시의 자료를 사용한다.
- max-age=0을 설정하여 매번 expire 캐시 엔트리를 재검증한다.
Expires
- max-age가 지정되지 않았으므로 Expires를 확인한다.
- Expires값을 과거로 설정되어 무조건 revalidating 하도록 하였다.
- Cache-Control 지시자에 no-cache, must-revalidate를 설정하여 캐시를 지나지 않고 무조건 origin서버에서 revalidate한 이후 response를 받는다.
Vary와 Accept-Encoding
- Accept Encoding에 giz, deflate를 주어 모든 요청을 gzip, deflate에 대한 요청으로 redirect한다.
- 캐쉬한 응답이 적절한 Accept-Encoding 요청 헤더를 보낸 클라이언트에게만 보내지도록 Vary: Accept-Encoding가 설정되었다.
출처 - http://icecreamie.tistory.com/52
JSP로 로그인 페이지를 만들다가 로그인 상태에서 뒤로가기를 누르면 이전에 캐쉬된 히스토리 페이지가 나타나서 로그인전의
페이지로 보이는 껄끄러운 작동이 구현되었다. (F5 새로고침으로 누르면 세션속성이 설정된 상태라 정상페이지가 나오기는 함)
그래서 관련사이트들을 탐방한결과 웹언어별 no-cache 설정법을 알아내게 되었다.
원리는 no-cache를 해당페이지에 설정함으로써 해당페이지에 대한 캐쉬를 생성하지 않아 해당페이지가 로드될때는 항상 새로운페이지로 로드되는 원리였다.
이를 이용해서 뒤로가기를 눌렀을때의 로그인상태를 유지하는 구현을 완성하였다.
다만, 이 방법이 정석이다 라고 생각해서는 안되는듯 하다.
웹브라우저에 따라 캐쉬가 되는 경우도 발생할수 있다는 글을 보았다.
(현제 IE8을 사용중인데 해당웹브라우저에선 정상 작동중이다.)
특별히 캐쉬를 생성하지 않아야 구현할 수 있는 상황에서만 사용을 해야할것 같아보인다.
추후 IE6,7 파이어폭스, 구글크롬 등에서도 정상작동을 하는지 확인 해보아야 겠다.
HTML
<META http-equiv="Expires" content="-1">
<META http-equiv="Pragma" content="no-cache">
<META http-equiv="Cache-Control" content="No-Cache">
ASP
<%
Response.Expires = 0
Response.AddHeader "Pragma","no-cache"
Response.AddHeader "Cache-Control","no-cache,must-revalidate"
%>
JSP
<%
response.setHeader("Cache-Control","no-store");
response.setHeader("Pragma","no-cache");
response.setDateHeader("Expires",0);
if (request.getProtocol().equals("HTTP/1.1"))
response.setHeader("Cache-Control", "no-cache");
%>
PHP
<?
header("Pragma: no-cache");
header("Cache-Control: no-cache,must-revalidate");
?>
추가내용) Struts Framework 에서는 struts-config.xml 설정파일에 단지 true로 설정해주면 Cache가 적용되지 않는다고 한다.
<controller nocache="true" /> 라는 설정을 struts-config.xml 에 추가해주면 된다고 한다.
출처 - http://cyzest.tistory.com/7