1. 캐시
캐시는 예시를 살펴보면, 이게 뭔지 감이 잡힐 것이다!
"캐시"가 없을 때, 웹 브라우저에서 star.jpg 요청 -> star.jpg 응답을 내려줌.
그 이후에 또 똑같이 star.jpg를 요청하면 -> 서버는 또 star.jpg를 응답으로 내려준다.
이 방식은 큰 단점이 있다.
- 데이터가 변경되지 않아도, 계속 네트워크를 통해 다운로드 받는다.
- 인터넷 네트워크는 매우 느리고 또 비싸다.
- 브라우저 로딩 속도가 느리다. -> 사용자 불편
그럼, 캐시를 도입하면 어떨까?
캐시가 있을 때, 웹 브라우저에서 star.jpg 요청 -> 서버는 응답 헤더에 cache-control: max-age=60이라는 헤더를 넣고 응답
이 말은, 60초동안 이 캐시가 유효하다는 뜻이며, 해당 캐시가 브라우저 캐시 저장소에 60초동안 저장하게 된다.
그럼 또 star.jpg 요청이 들어왔을 때 -> 캐시를 먼저 뒤져보고, 없으면 네트워크를 타고 서버에게 요청이 들어가게 된다.
캐시를 사용하게 되면 위에서 언급한 단점들이 보완될 수 있다.
- 캐시 덕분에 캐시 가능 시간동안 네트워크를 사용하지 않아도 된다.
- 비싼 네트워크 사용량을 줄일 수 있다.
- 브라우저 로딩 속도가 매우 빠르다.
그럼, 만약 위의 경우처럼 60초동안 캐시를 유효화한 후, 60초가 지나면?
당연히 또 새로운 요청을 보내는 것이 맞다. 서버를 통해 데이터를 다시 조회하고, 또 다시 캐시를 갱신하면 된다.
2. 검증 헤더와 조건부 요청 1
앞서 말한 캐시 시간 초과에 대해 더 복잡한 상황을 생각해볼 수 있다.
<캐시 유효 시간이 초과해서 서버에 다시 요청하면, 다음 두 가지 상황이 존재할 수 있다>
(1) 서버에서 기존 데이터를 변경함.
(2) 서버에서 기존 데이터를 변경하지 않음.
(1) 의 경우에는 사실상 그냥 다시 요청을 갱신하면 된다.
60초 지났고, 데이터도 바뀌었으니, 새로 네트워크로 통신하여 데이터를 다운로드 받는 것이 맞다.
그럼, (2)의 경우를 생각해보자.
캐시 만료 후에도 서버에서 데이터가 변경되지 않았다면, 데이터를 전송하는 대신 저장해 두었던 캐시를 재사용하면 된다.
단, 클라이언트의 데이터와 서버의 데이터가 같다는 사실을 확인할 수 있는 방법이 필요하다.
위 사진은 정말 처음, 웹 브라우저가 star.jpg를 요청한 상황이다.
웹 브라우저가 /star.jpg를 요청한다.
-> 서버의 Last-Modified 헤더를 보자. 서버의 응답 메시지에는 해당 star.jpg의 마지막 수정일자를 제시한다.
이 응답을 웹 브라우저 캐시 저장소에 저장한다.
그리고 60초가 초과되었다.
초과된 이후, 웹 브라우저는 또 star.jpg를 서버에게 요청하는데
이때 요청 메시지에 if-modified-since 조건부 요청 헤더를 넣어 캐시가 가지고 있는 데이터의 최종 수정일 담아 전송하게 된다.
그럼 서버에서는 해당 요청 메시지와 본인이 가지고 있는 star.jpg의 last modified 시간과 대조해본다.
비교해보니, 최종 수정일이 동일하다? -> "데이터가 수정되지 않았다"
그럼, 서버는 응답 메시지에 304 Not Modified 상태 코드를 담아 클라이언트에게 전송한다.
애초에 요청이 if-modified-since: 만약 수정이 되었다면 이므로, 304 Not Modified가 전송되는 것이다.
그리고 응답 메시지의 Body에는 아무것도 담기지 않는다. 오직, 헤더만 전송되는 것이다.
(어차피 데이터는 수정되지 않았고, 똑같으니까)
그리고 위의 응답 메시지에서 나타난 것처럼 캐시는 다시 60초동안 유효하도록 브라우저 캐시 저장소에 저장된다.
3. 검증 헤더와 조건부 요청 2
"검증 헤더"는 결국 캐시 데이터와 서버 데이터가 같은지 검증하는 데이터이다.
방금은 "Last-Modified" 검증 방식을 설명했으며, 이제는 ETag를 사용한 방식을 살펴볼 것이다.
"조건부 요청 헤더"는 검증 헤더로, 조건에 따른 분기를 정하게 된다.
- If-Modified-Since : Last-Modified 사용
- If-None-Match : ETag 사용
- 조건이 만족하면 200 OK
- 조건이 만족하지 않으면 304 Not Modified
즉, "If-Modified-Since : 이후에 데이터가 수정되었으면?" 을 의미한다.
데이터가 수정되었으면 200 OK, 수정되지 않았으면 304 Not Modified인 것이다. (이 경우 Body는 미포함)
그런데, 앞서 봤던 If-Modified 방식은 1초 미만 단위로 캐시 조정이 불가능하다. (날짜 기반의 로직)
- 데이터를 수정해서 날짜가 다르지만? 수정했다가 다시 원래대로 수정했을 수도 있다.
- 서버에서 별도의 캐시 로직을 관리하고 싶을 수도 있다.
그래서 ETag, If-None-Match 로직을 사용할 수 있다.
- ETag(Entity Tag) : 캐시용 데이터에 임의의 고유한 "버전 이름"을 달아둔다.
ex) ETag: "v1.0", ETag: "a2jiodwjekil3" - 데이터가 변경되면, 이 버전 이름을 바꾸어서 변경하면 된다.
ex) ETag: "aaaaa" -> ETag: "bbbbb"
위 상황은 웹 브라우저에서 "처음" star.jpg를 요청한 상황부터 시작한다.
웹 브라우저에게 GET /star.jpg 요청이 들어오면
-> 서버는 ETag: "aaaaaaaaaa" 헤더를 포함하여 메시지 헤더와 바디를 응답으로 전달한다.
그럼 똑같이 이전과 똑같이 응답 결과가 브라우저 캐시 저장소에 저장된다.
60초가 초과되기 전에 또 똑같이 요청을 보내면 해당 캐시에서 꺼내서 웹 브라우저에게 star.jpg가 보여지면 된다.
그럼, 60초가 초과된 후 웹 브라우저가 /stat.jpg를 요청하면
웹 브라우저의 조건부 요청 헤더와 함께 ETag 정보가 서버에게 전송된다.
-> 서버는 자신이 가진 데이터의 ETag 버전 이름을 비교한다.
다행히 아직 수정되지 않았다.
그러면 If-None-Match: "aaaaaaaaaa"의 요청에서, None-Match가 "아니므로"
304 Not Modified 상태 코드를 담아 웹 브라우저에게 전달하면 된다.
- 당연히 캐시는 다시 갱신되어야 하므로 cache-control: max-age=60 헤더가 전송되어야하며
- 캐시의 버전은 동일하므로, 헤더만 전송되고 Body에 데이터는 보내지 않는다.
- 해당 방식은 정말 단순하게 ETag만 서버에 보내서, 같으면 유지 / 다르면 다시 받는다.
-> 캐시 제어 로직을 서버에게 완전히 위임한 것이라 볼 수 있다. - 클라이언트는 단순히 이 값을 서버에 제공만 하므로 클라이언트는 캐시 메커니즘을 모른다.
ex) 서버는 배타 오픈 기간인 3일 동안 파일이 변경되어도 ETag를 동일하게 유지
4. 캐시 지시어
Cache-Control 헤더란, 서버가 클라이언트나 프록시 서버에 응답을 보낼 때 포함하는 HTTP 응답 헤더인데,
응답 데이터가 어떻게 캐시되고, 얼마나 오래, 어떤 조건에서 사용할 수 있는지를 명시함을 앞에서 계속 살펴봤다.
이 헤더에 다른 지시어들을 사용할 수 있다.
- Cache-Control: max-age
- 캐시 유효 시간, 초단위로 설정 가능하다. - Cache-Control: no-cache
- 데이터는 캐시해도 되지만, 항상 원(origin) 서버에 검증하고 사용해야 한다. (proxy cache가 안된다는 뜻) - Cache-Control: no-store
- 데이터에 민감한 정보가 있으므로 저장하면 안된다.
[참고] : 인프런-김영한 <모든 개발자를 위한 HTTP 웹 기본 지식>
'HTTP' 카테고리의 다른 글
[HTTP] 쿠키 (3) | 2024.12.17 |
---|---|
[HTTP] Header | 일반 헤더 1 (0) | 2024.12.15 |
[HTTP] HTTP 상태 코드 (2) | 2024.12.15 |
[HTTP] HTTP 메서드 활용 | 정적 / 동적 데이터 | HTML Form | HTTP API (3) | 2024.12.15 |
[HTTP] HTTP Method (3) | 2024.12.12 |