HTTP 헤더 - 캐시와 조건부 요청

Aiden·2022년 3월 19일
1

HTTP

목록 보기
13/13
post-thumbnail

이번 포스팅에서는 일반 헤더를 정리했던 이전 포스팅에 이어서 캐시와 조건부 요청 관련 헤더들에 대해 다루어보려고 한다.



캐시 기본 동작


캐시와 조건부 요청에 관련된 헤더들을 살펴보기 앞서, 캐시의 기본 동작에 대해 간단히 알아보고 넘어가자.

❌ 캐시가 없을 경우

1. 첫 번째 요청

  • 클라이언트가 서버에게 jpg 파일에 대해 요청

  • 서버는 Body 에 파일을 담아 클라이언트로 전송

  • 이 때, HeaderBody 포함 메시지 크기는 1.1 M 로 가정

2. 두 번째 요청

  • 클라이언트가 서버에게 이전과 동일한 jpg 파일에 대해 요청

  • 서버는 Body 에 파일을 담아 클라이언트로 전송

  • 이 때, HeaderBody 포함 메시지 크기는 1.1 M 로 첫 번째 요청과 동일

💡 문제점

  • 데이터가 변경되지 않아도 계속 네트워크를 통해서 데이터를 다운로드 받아야 한다.

  • 브라우저 로딩 속도가 느리다.



⭕ 캐시 적용

1. 첫 번째 요청

  • 클라이언트가 서버에게 jpg 파일에 대해 요청

  • 서버는 Body 에 파일을 담아 클라이언트로 전송

  • 이 때, Header 와 Body 포함 메시지 크기는 1.1 M 로 가정

  • 클라이언트는 전달받은 파일을 캐시에 저장

2. 두 번째 요청

  • 클라이언트가 이전과 동일한 jpg 파일을 캐시에서 참조

💡 장점

  • 동일한 데이터를 캐시에 저장해두고 이를 참조하여 불필요한 네트워크 다운로드 효과적 감소

  • 브라우저 로딩 속도가 빠름


이렇게, 캐시를 사용하게 되면 서버로부터 불필요한 네트워크 다운로드를 효과적으로 줄일 수 있다.
한 번 응답받았던 데이터는 브라우저의 캐시 저장소에 남아 일정 시간 내에 계속해서 참조할 수 있기 때문이다.
이는 결과적으로 네트워크 다운로드 용량을 줄이는 것 뿐 아니라, 브라우저의 로딩 속도를 개선해 더 빠른 사용자 경험이 가능하도록 한다.



HTTP 헤더 - 캐시와 조건부 요청


이제 캐시와 조건부 요청 관련 헤더들을 본격적으로 알아보자.

💡 캐시 제어

📌 Cache

  • Cache-Control
  • Pragma
  • Expires

Cache-Control

캐시의 유효 시간을 명시하는 헤더로, 유효 시간이 초과되면 캐시 데이터를 사용할 수 없기 때문에 원칙적으로 다시 네트워크 다운로드를 통해 데이터를 받아와야 한다.

  • 캐시의 유효 시간

    • 초 단위로 지정
    • 응답 시 사용
  • Parameters

    • max-age : 캐시 유효 시간, 초 단위
    • no-cache : 데이터는 캐시해도 되지만, 항상 Origin Server 에 검증후 사용
    • no-store : 데이터에 민감한 정보가 포함되어 있어 저장 불가 혹은 최대한 빨리 삭제
    • public : public 캐시(프록시 캐시 서버)에 저장 가능
    • private : public 캐시에 저장 불가
    • s-maxage : 프록시 캐시 서버에 적용되는 max-age
    • Age : Origin Server 의 응답이 프록시 캐시 서버에 머문 시간(sec)
    • must-revalidate : 캐시 만료후 최초 조회시 Origin Server 에 검증

ex) cache-control: max-age=60 . . .


Pragma

현재는 HTTP 1.0 하위 호환을 위해 사용하는 캐시 제어 헤더이다. Cache-Control 과 동일한 역할을 수행하지만 권장되지 않는다.

ex) pragma: no-cache . . .

Expires

캐시의 만료일을 명시하는 헤더로, 정확한 날짜를 지정하여야 한다.
유효 시간을 명시하는 Cache-Control 과 비교하여 유연하지 않다는 단점이 있어 권장되지 않고, 현재는 하위 호환을 위해 사용되는 캐시 제어 헤더이다.

ex) expires: Wed, 21 Oct 2015 07:28:00 GMT . . .

💡 검증

📌 Validation

  • Last-Modified
  • ETag

Last-Modified

검증 헤더Last-Modified 는 데이터의 최종 수정 시각을 명시한다. 클라이언트가 캐시 유효 기간이 초과된 데이터를 서버에 요청하는 경우, 이를 기준으로 데이터가 수정되었는지 검증할 수 있다.
즉, 서버의 데이터 최종 수정 시각이 Last-Modified 보다 이후라면, 데이터가 수정된 것으로 간주하고, 서버의 데이터 최종 수정 시각이 Last-Modified 와 같다면, 데이터가 수정되지 않은 것으로 간주한다.
If-Modified-Since 와 함께 사용된다.

  • 데이터가 마지막에 수정된 시간

    • 응답 시 사용
    • 데이터의 최종 수정 시간
    • If-Modified-Since 와 함께 사용

ex) last-modified: Tue, 15 Mar 2022 06:48:06 GMT . . .


ETag

하지만, Last-Modified 는 단순히 최종 수정 시각을 기준으로 데이터의 변경 및 수정을 검증하기 때문에 A -> B -> A 와 같은 동일 데이터로의 변경은 검증해내지 못한다는 한계점이 있다.
따라서 검증 헤더ETag 를 사용하면, 서버에서 별도의 캐시 로직을 관리할 수 있으며, 해시값을 활용해 콘텐츠를 기반으로 정확하게 검증할 수도 있다.
데이터가 변경되면 ETag 가 변경되기 때문에, 단순히 ETag 가 같으면 데이터가 수정되지 않은 것이고, ETag 가 다르면 데이터가 수정된 것으로 간주하게 된다.
If-None-Match 와 함께 사용된다.

  • 데이터의 고유 식별값

    • 응답 시 사용
    • 데이터의 버전 이름 혹은 해시값
    • If-None-Match 와 함께 사용

ex) ETag: "a2jiodwjekjl3" , ETag: "v1.0" . . .


💡 조건부 요청

📌 Conditional Requests

  • If-Modified-Since
  • If-Unmodified-Since
  • If-None-Match
  • If-Match

If-Modified-Since

조건부 요청 헤더If-Modified-Since 는 클라이언트의 요청 시 사용되며, 서버의 데이터 최종 수정 시각과 캐시 데이터의 Last-Modified 를 비교하여 데이터 수정 여부를 확인하기 위해 사용한다.

이 때, 데이터가 수정되지 않았다면 이전 캐시를 재사용하게 되고, 데이터가 수정되었다면 새로운 데이터를 Body 에 담아 전송받게 된다.

  • 데이터가 Last-Modified 이후로 수정되었는지 확인

    • 캐시 유효 시간이 만료되더라도, 서버의 데이터가 수정되지 않았다면 캐시 재사용 가능
    • 수정되지 않았다면 304 Not Modified 응답 ---> 캐시 재사용
    • 수정되었다면 200 OK 응답 ---> Body 에 새로운 데이터 전송 (네트워크 다운로드)
    • 요청 시 사용
  • 단, 304 Not Modified 응답 메시지에 Body 사용 불가

    • 클라이언트가 캐시 데이터를 사용하여야 하기 때문



If-None-Match

조건부 요청 헤더If-None-Match 는 클라이언트의 요청 시 사용되며, 서버의 데이터 ETag 와 캐시 데이터의 ETag 를 비교하여 데이터 수정 여부를 확인하기 위해 사용한다.

이 때, 데이터가 수정되지 않았다면 이전 캐시를 재사용하게 되고, 데이터가 수정되었다면 새로운 데이터를 Body 에 담아 전송받게 된다.

  • 데이터의 ETag 를 기준으로 수정되었는지 확인

    • 캐시 유효 시간이 만료되더라도, 서버의 데이터가 수정되지 않았다면 캐시 재사용 가능
    • 수정되지 않았다면 304 Not Modified 응답 ---> 캐시 재사용
    • 수정되었다면 200 OK 응답 ---> Body 에 새로운 데이터 전송 (네트워크 다운로드)
    • 요청 시 사용
  • 단, 304 Not Modified 응답 메시지에 Body 사용 불가

    • 클라이언트가 캐시 데이터를 사용하여야 하기 때문



⚠️ If-Unmodified-SinceIf-Match ?

If-Unmodified-SinceIf-Match 는 각각 If-Modified-Since, If-None-Match 와 반대의 역할을 수행한다.
하지만 Last-ModifiedETag 를 기준으로 데이터의 수정 여부를 확인하는 헤더인 것은 동일하다.


⚠️ 캐시 무효화

만약, 캐시를 사용해선 안되는 페이지가 존재한다면, 다음과 같이 Setup 하여야 한다.

  • Cache-Control: no-cache, no-store, must-revalidate
  • Pragma: no-cache

이 때, must-revalidate 가 사용되는 이유는 no-cache 에 의해 Origin Server 에 검증 요청을 보내는 도중 Origin Server 와 Proxy Cache Server 의 연결이 끊어져 검증이 불가능할 경우, 504 Gateway Timeout 오류를 발생시키기 위해서이다.

몇몇 Proxy Cache Server 에서는 Origin Server 에 접근이 불가능해질 경우에 검증을 거치지 않고 이전의 캐시 데이터를 반환하기 때문이다.

특히, 통장 잔고와 같은 중요 데이터의 경우, Origin Server 와의 연결이 불가능하다고 해서 변경 전의 데이터를 반환할 수는 없으므로 must-revalidate 를 활용해 오류를 발생시키기도 한다.

따라서, 캐시를 사용해서는 안되는 페이지의 경우에도 must-revalidate 를 명시하여 Proxy Cache Server 가 자체적으로 캐시 데이터를 반환하는 케이스를 사전에 차단하여야 한다.

추가적으로, Pragma: no-cache 의 경우에는 과거 HTTP 1.0 버전의 호환을 고려하였다고 볼 수 있다.


이렇게 캐시와 조건부 요청 관련 헤더들을 정리하면서 마지막 HTTP 시리즈 포스팅을 마치게 되었다.



출처


  • 김영한 님의 강의 모든 개발자를 위한 HTTP 웹 기본 지식 을 정리한 포스팅입니다.

0개의 댓글