HTTP 헤더와 캐시

Seongho·2023년 3월 14일
0

WEB

목록 보기
9/10

브라우저 캐시

웹 브라우저에서 서버로 어떤 동영상 파일을 요청했다고 해보자. 해당 동영상은 1MB라고 치고, 서버에서 응답 메세지를 보낼 때, HTTP 헤더가 0.1M, 바디가 1M로, 총 1.1M 크기의 응답 메세지가 전송된다. 만약, 브라우저에서 이 요청을 계속 한다고 치면, 데이터가 바뀌지 않았는데, 1.1M의 같은 응답을 서버에서 계속 보내고 브라우저에서 계속 다운받는 낭비가 발생한다. 실제로 인터넷 네트워크 비용은 매우 큰데, 이로 인해 브라우저 로딩 속도가 느려진다. 이를 해결하기 위해 캐시를 사용한다.




캐시 시간 초과가 발생하면 어떻게 될까?

캐시 시간 초과

  1. 서버에서 기존 데이터를 변경하지 않은 경우
  2. 서버에서 기존 데이터의 변경이 일어난 경우
    1과 2의 상황에서의 동작이 다르다. 서버에서 데이터 변경이 일어나지 않으면, 시간 초과된 캐시를 재사용하면 된다. 단, 서버에서 데이터 변경이 일어났는지, 아닌지에 대한 검증이 필요하다. 검증헤더를 사용하여 검증할 수 있다.

검증헤더1 : Last-Modified

서버에서 응답 메세지에 Last-Modifed 정보를 헤더에 추가한다.

브라우저에서 요청 메세지를 보낼 때, 캐시에 시간 초과가 되면 요청메세지에 if-modified-since에 캐시에 저장된 데이터 최종 수정 시간을 가져와 헤더에 추가하여 서버에 요청 메세지를 보낸다.

서버에서는 요청 메세지의 if-modified-since 정보와 서버의 데이터 최종 수정 시간 정보를 확인한 후, 일치하면 데이터 수정이 일어나지 않았으므로 캐시를 재사용하도록 304 Modified 에러를 전송한다. 이 때, 응답 메세지에 Body는 없다.

검증헤더1의 아쉬운 점

  • 날짜 기반 로직을 사용하여 가장 작은 단위가 초 단위이기 때문에, 1초 미만의 단위로 캐시를 조정할 수 없고, 데이터를 수정해서 날짜가 달라졌지만, 결국 데이터가 같은 경우, 캐시를 재사용할 수 있는데 이를 구분할 수 없다. 또한, 주석같이 데이터에 별 영향을 안미치는 것들이 변경되었을 때 캐시를 재사용하고 싶은데 이를 구분할 수 없다.

검증헤더2 : ETag

서버에서 데이터를 구분하기 위해 ETag에 버전을 임의로 저장하여 응답 메세지를 보낸다. ETag는 서버의 데이터가 변경되면 갱신된다.

브라우저에서 요청을 보낼 때, 캐시가 시간 초과되면 If-None-Match에 캐시에 들어있는 ETag 값을 입력하고 서버에 요청 메세지를 보낸다.

요청 메세지에 담긴 ETag 값과 서버의 ETag값이 같으면 304 Not Modified 에러를 전송한다.


ETag의 장점은 캐시 제어 로직을 서버에서 완전히 관리한다는 것이다. 따라서 클라이언트는 단순히 ETag값을 서버에 전달하는 것 뿐이다. ETag는 주로 애플리케이션 배포 주기에 맞추어 ETag를 모두 갱신하는 일에 사용된다.

프록시 캐시


만약, YouTube를 볼 때, 한 영상을 볼 때 브라우저에서 origin 서버와 통신하여 영상을 다운로드하는데 0.5초가 걸린다고 했을 때, 각 클라이언트 모두 영상을 다운로드하는데 0.5초씩 계속 걸리게 된다.

따라서, 중간에 프록시 캐시 서버를 두어, 한 클라이언트에서 origin 서버에 접근하면 프록시 캐시 서버에 데이터를 저장해두고, 각 클라이언트들은 프록시 캐시 서버에 접근하도록 한다.
이 때, 클라이언트에 있는 캐시는 private cache, 프록시 서버 캐시는 public cache 라고 한다.

캐시 무효화

캐시를 무효화해야 하는 상황. 즉, 캐시에 데이터를 저장하면 안되는 상황이 있다. 예를 들면, 주민등록번호와 같은 데이터이다. 이 때는
Cache-Control: no-cache, no-store, must-revalidate
Pragma: no-cache
(HTTP 1.0 하위 호환을 위해 사용)
이 두 가지를 모두 사용해야 한다.

Cache-Control: no-cache

데이터는 캐시해도 되지만, 프록시 서버가 아닌 origin 서버에 검증하고 사용한다.

Cache-Control: no-store

데이터에 민감한 정보가 있으므로 메모리에서 사용하고 최대한 빨리 삭제한다. 즉, 캐시에 저장하지 않는다.

Cache-Control: must-revalidate

캐시 만료 후 최초 조회 시 origin 서버에 검증을 받아야 한다. 이 때, origin 서버 접근 실패 시 504 에러를 발생시킨다.

Pragma: no-cache

HTTP 1.0 하위 호환을 위해 사용한다.

no-cache vs must-revalidate


no-cache 에서는 origin 서버에 접근 불가 시 종종, 프록시 캐시 서버에 따라 프록시 캐시 서버에 저장되어 있던 이전의 데이터를 보여주는 경우가 있다.

must-revalidate 에서는 504 에러를 발생시킨다.

이렇게 네 가지를 모두 써서 캐시를 막는 이유

만약, 은행 계좌에 접근하는 요청을 한다고 치자. 만약, 어떤 이유로 프록시 캐시 서버와 origin 서버 간에 네트워크 연결이 끊겼을 때, 남은 잔액을 이전에 저장했던 잔액으로 응답을 보내면 큰 문제가 생길 것이다.
따라서, 캐시를 무효화 해야하는 상황에서는
Cache-Control: no-cache, no-store, must-revalidate
Pragma: no-cache

이렇게 사용해야 한다.

** 인프런 HTTP 강의 (김영한) 참고

profile
Record What I Learned

0개의 댓글