HTTP 헤더 - 캐시와 조건부 요청 헤더
캐시와 조건부 요청 헤더에 대해 알아보기 위해
캐시에 대해서 먼저 알아보겠습니다
캐시란(Cache)?
자주 사용하는 데이터나 값을 미리 복사해 놓는 임시 장소를 가리킵니다.
반복적으로 동일한 결과를 돌려주는 경우나 빠른 속도로 데이터에 접근하기 위해 사용합니다.
캐시를 왜 사용할까요?
웹 브라우저가 서버에게 1MB짜리 이미지를 요청한다고 가정하겠습니다.
이때 네트워크에서 HTTP 헤더의 전송 비용은 0.1MB라고 가정하겠습니다.
캐시를 사용하지 않을 때
사용자가 브라우저를 새로고침 하거나 접속할 때마다 1MB의 이미지를 계속 요청해야 합니다.
그렇게 되면 전송 비용이 HTTP 헤더 + HTTP 바디 = 1.1MB가 계속 요청됩니다.
만약에 클라이언트가 서버에게 이미지를 100번 요청한다면 1.1MB * 100의 전송 비용이 됩니다.
캐시를 사용할 때
사용자가 브라우저를 새로고침 하거나 접속할 때마다 캐시에 데이터가 있는지 검사합니다.
첫 요청에는 캐시가 존재하지 않기 때문에 웹 브라우저가 서버에 이미지를 요청합니다.
그렇게 되면 서버의 응답 결과가 캐시에 일정 시간 저장됩니다.
다음 요청에는 우선 캐시에 데이터가 있는지 검사합니다.
만약에 캐시가 저장되고 있는 일정 시간 안에 클라이언트가 이미지를 100번 요청한다면 0.1MB * 100 의 전송 비용이 됩니다.
즉, 캐시를 사용하지 않으면 인터넷 네트워크 비용이 증가하고 사용자 또한 브라우저의 로딩이 느린 경험을 합니다.
캐시의 시간이 초과되었을 때
캐시 유효 시간을 초과하여 서버에 다시 요청하면 두 가지 상황이 존재합니다.
1. 서버에서 기존 데이터를 변경함
변경된 데이터를 다시 받아와야 함
2. 서버에서 기존 데이터를 변경하지 않음
데이터가 변경되지 않았는데 캐시의 유효 시간이 초과되어 서버에게 다시 데이터를 받는 것이 비효율적이라고 생각되어 캐시를 검증하는 헤더가 등장하게 됩니다.
데이터가 마지막에 수정된 시간을 기록하는 검증 헤더를 사용하여 서버에게 전달합니다.
서버와 클라이언트가 가지고 있는 데이터의 수정된 시간을 비교하여 만약에 날짜가 변경되지 않았다면 데이터가 변경되지 않습니다.
서버는 HTTP 바디가 없고 HTTP 헤더만 존재하는 응답 메시지를 보냅니다.
이 응답 메시지의 상태 코드는 304 Not Modified로 클라이언트는 응답 메시지를 통해 데이터가 변경되지 않았음을 알게 되고 캐시의 유효 시간을 갱신하며 캐시에 저장되어 있는 데이터를 재사용하게 됩니다.
네트워크 비용이 발생하긴 하지만 용량이 적은 헤더 정보로만 다운로드할 수 있는 실용적인 해결책입니다.
데이터를 수정하였지만 수정 날짜만 다르고 데이터 결과가 같은 경우
데이터는 같지만 마지막에 수정된 시간이 다르므로 위의 방식대로 한다면 서버의 응답 메시지는 200 OK를 보내고 클라이언트는 캐시를 사용하지 못합니다.
이때는 캐시용 데이터에 임의의 고유한 버전 이름을 사용합니다.
이를 ETag라고 합니다.
ETag 헤더를 사용하여 Etag가 같다면 캐시를 사용하고 Etag가 다르다면 서버에서 데이터를 받아서 사용합니다.
하지만 캐시를 사용한다고 해도 한국에 있는 클라이언트와 미국에 있는 원 서버가 통신하기 위해서는 시간이 오래 걸립니다.
프록시 캐시가 도입됩니다.
한국 어딘가에 프록시 캐시 서버를 두어 웹 브라우저가 미국의 원 서버로 요청하는것이 아니라 응답이 빠른 한국의 프록시 캐시를 이용하여 캐시를 받습니다.
프록시 서버를 통한 캐싱 과정
1. 첫 번째로 이용하는 유저는 프록시 캐시 서버에 데이터를 요청하여도 프록시 캐시 서버에 데이터가 존재하지 않습니다.
2. 프록시 서버가 원 서버에 데이터를 요청하여 사용자에게 전달하고 이를 프록시 서버에 저장합니다.
3. 다른 유저가 같은 데이터를 요청하게 되면 프록시 서버를 이용하여 데이터를 전달합니다.
캐시 헤더
Cache-Control: max-age = 60 ( 캐시 유효 시간, 초 단위)
Cache-Control: no-cahge (캐시를 사용해도 되지만 항상 서버에서 검증하고 사용해야 함)
Cache-Control: no-store (데이터가 민감한 정보이므로 저장하면 안 됨)
Cache-Control: public (응답이 public 캐시에 저장되어도 됨)
Cache-Control: private (응답이 해당 사용자만을 위한 것이어서 private 캐시에 저장해야 함)
Cache-Control: s-maxage (프록시 캐시에서만 적용되는 max-age)
Age: 60 (오리진 서버에서 응답 후 프록시 캐시 내에 머문 시간)
검증 헤더
캐시 데이터와 서버 데이터가 같은지 검증하는 데이터
Last-Modified: 2020년 11월 10일 10:00:00
ETag: "aaaaaaaa"
조건부 요청 헤더
검증 헤더로 조건에 따른 분기로
조건이 만족하면 200 OK (캐시를 사용하지 않고 서버에서 HTTP BODY를 받아옴)
조건이 만족하지 않으면 304 Not Modified(서버에서 HTTP BODY를 받아 오지 않고 캐시를 사용함)
if-Modified-Since: 2020년 11월 10일 10:00:00 (서버와 데이터 수정 시간이 같으면 304, 같지 않으면 200)
If-None-Match : "aaaaaaaaa" (서버와 ETag가 같으면 304, 같지 않으면 200)
마찬가지로 if-Match, if-Unmodified-Since도 존재합니다. (위의 헤더와 분기가 반대)
만약에 캐시를 적용하고 싶지 않다면
사용자의 통장잔고 같이 계속 갱신이 되는 것은 캐시를 적용하면 안 됩니다.
그 경우에는 아래와 같이 해야 합니다.
Cache-Control: no-cache, no-store, must-revalidate
Pragma: no-cache
이는 항상 원 서버에 검증하고 사용해야 하고, 저장하면 안 되며, 원 서버 접근 실패 시 반드시 오류가 발생해야 합니다 라는 뜻입니다.
must-revalidate를 사용하지 않으면 프록시 서버와 원 서버에서 순간 네트워크가 단절되었을 때 오류가 나는 것보다는 오래된 데이터라도 보여주기 위해 200 OK를 하는 경우가 있지만 must-revalidate를 사용한다면 항상 504 Gateway Timeout 오류가 발생합니다.
출처
https://www.inflearn.com/course/http-%EC%9B%B9-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC