Http

HTTP Header(헤더)- 캐시, 조건부 요청

녁이 2023. 7. 31. 00:51
728x90
반응형

2023.07.28 - [Http] - HTTP Header(헤더)의 구조, 쿠키

 

HTTP Header(헤더)의 구조, 쿠키

HTTP Header는 왜 쓰일까? → HTTP 헤더는 인터넷 상에서 HTTP 프로토콜을 이용해 데이터를 전송하는 HTTP 전송에 필요한 모든 부가 정보를 전달하기 위해 존재한다. ( 메시지 바디의 내용, 메시지 바디

junhyuk-develop.tistory.com

Http Header 의 기본적인 구조와 종류, 그리고 추가적으로 쿠키에 대해서 설명한 글이다.

이글을 읽기 앞서 보고 온다면 이해하는데 더 수월할 수 있다.


Cache(캐시)가 없다면 어떤 일이 일어날까? 캐시를 사용하면 뭐가 좋을까?

이해를 위해 예시를 하나 들겠다.

캐시가 없는 세상에서, 웹 사이트로부터 하나의 이미지 형태를 읽어오기 위해선 서버에 GET 형태로 요청을 보내야한다.

그러면 서버에서는 HTTP 응답 헤더를 보내야하는데, 이미지에 관한 데이터를 HTTP 바디에 담아서 보내게 된다.

그러면 클라이언트는 이미지 데이터를 받아 확인할 수 있게 된다.

여기까지가 최초의 이미지 데이터 요청 상황이다.

 

그렇다면, 이 이미지 데이터를 또 확인하고 싶다면 어떻게 해야 될까?

캐시가 없기 때문에, 다시 서버에 GET 형태로 이미지 데이터를 요청해야 한다.

그러면 서버는 다시 또 이미지 데이터를 HTTP 바디에 담아서 보내줄 것이고 클라이언트는 똑같은 이미지를 다시 또 받게 될 것이다.

 

캐시가 없는 세상은 값비싼 인터넷 네트워크를 이러한 반복 작업 때문에 낭비하게 될 것이고, 브라우저는 로딩 속도가 굉장히 느릴 것이며, 사용자는 느린 인터넷을 경험하게 될 것이다.

 

그렇다면, 이 비효울적인 상황을 해결하기 위해선 뭐가 필요할까?

그게 바로 Cache(캐시) 이다.


캐시의 작동 원리

캐시는 일단 HTTP 헤더에 Cache와 관련된 필드를 사용한다. 또한, 웹 브라우저(클라이언트) 내에 브라우저 캐시 저장소를 이용한다.

이게 무슨 말이냐? 위에서 말한 예시를 다시 들겠다.

최초에 상황은 위와 마찬가지로, 클라이언트는 이미지 데이터에 대한 GET 요청을 서버로 보낼 것이고 서버는 이에 대한 HTTP 응답을 보낼 것인데, 이 응답의 바디 부분에는 이미지 데이터가 포함되어 있을 것이다.

이를 받은 클라이언트는 이미지 데이터를 통해 이미지를 읽어올 수 있는 것이다.

 

그리고, 이 이후로 캐시가 사용이 된다.

서버는 HTTP 응답 메세지의 헤더 부분에 Cache-control 필드를 통해 캐시 데이터의 유효 기간을 설정하여 클라이언트로 보낸다.

웹 브라우저는 응답 결과를 확인하여 브라우저 캐시 공간에 캐시 데이터로 저장하게 된다. 해당 캐시 데이터는 응답 헤더의 Cache-control 필드에 적혀있는 유효 기간만큼 동안만 유효하다.

 

캐시 데이터가 저장된 이후로, 또 같은 이미지 데이터에 대한 요청을 한다면, GET 요청을 하기 이전에 클라이언트의 PC에 있는 브라우저 캐시 공간을 확인하여 캐시 유효 기간을 검증하여 사용이 가능하다면, 서버로 요청을 보내지 않고 이를 사용하게 된다. ( 캐시 시간이 초과되면 서버로 재요청 후 새로 받은 데이터를 캐시 데이터로 저장 )

 

캐시 덕분에 캐시 가능 시간동안 네트워크를 사용하지 않아도 되므로 비싼 네트워크 사용량을 줄일 수 있다.
또한, 불필요한 정보의 교환이 줄어드므로 브라우저의 로딩 속도가 매우 빨라지며 사용자는 빠른 인터넷을 경험하게 된다.

 


캐시 시간 초과

캐시 시간이 초과되면 위에서 말했듯이 서버로 재요청을 하고 새로 받은 데이터를 캐시 데이터로 저장하게 된다.

그런데, 새로 받은 데이터가 기존 데이터와 똑같을 수도 있고 다를 수도 있다.

그러면, 이런 생각이 들것이다. 아니.. 데이터가 똑같으면 굳이 또 서버로부터 그 많은 데이터량을 다운받아야 할까..?

원래 쓰던 데이터를 재사용하면 되지 않을까?

단, 클라이언트의 데이터와 서버의 데이터가 같다는 사실을 확인해야 한다.

이때 사용되는게 검증 헤더와 조건부 요청이다.


검증 헤더와 조건부 요청

  • 검증 헤더
    • 캐시 데이터아 서버 데이터가 같은지 검증하는 데이터
    • Last_Modified, ETag
  • 조건부 요청 헤더
    • 검증 헤더로 조건에 따른 분기
    • If-Modified-Since : Last-Modified 사용
    • If-None-Match : ETag 사용
    • 조건이 만족하면 200 OK
    • 조건이 만족하지 않으면 304 Not Modified

 

클라이언트의 데이터와 서버의 데이터가 같다는 걸 위해 검증 헤더를 HTTP 응답 헤더에 추가한다.

Last-Modified 필드를 통해 데이터가 마지막으로 수정된 시간을 함께 보내는 것이다.

최초의 요청 이후로 요청이 새로 올때마다 서버가 이 필드를 확인하여 변경된 데이터를 보낼지, 변하지 않았으니 가지고 있는 데이터를 재사용하라고 보낼지 정하게 된다.

 

서버는 클라이언트의 요청 메세지에 데이터 최종 수정일을 확인하여 본인의 데이터와 동일하다면, 304 Not Modified를 보내면서 HTTP 메세지 바디를 포함하지 않고 HTTP 헤더만 전송하게 된다.

반대로, 본인의 데이터와 클라이언트의 캐시 데이터가 다르다면? → 응답 헤더에 200 OK 를 보내면서 HTTP 바디를 포함하여 변경된 데이터를 전송하게 된다.

 

그러나, Last-Modified, If-Modified-Since 의 단점도 있다.

  • 1초 미만의 단위로 캐시 조정이 불가능
  • 날짜 기반의 로직 사용 ( ex. 7월 8일 )
  • 데이터를 수정해서 날짜가 다르지만, 같은 데이터를 수정해서 데이터 결과가 똑같은 경우 ( A B A )
  • 서버에서 별도의 캐시 로직을 관리하고 싶은 경우

해당 단점을 해결하기 위한 해결책은 ETag(Entity Tag), If-None-Match 이다.

ETag

  • 캐시용 데이터에 임의의 고유한 버전 이름을 달아둠
    • 예) ETag : "v1.0", ETag : "a2jiodwidekf3"
  • 데이터가 변경되면 이름을 바꿔서 변경함 ( Hash를 다시 생성 )
    • 예) ETag : "aaaa" ETag : "bbbb"
  • 단순하게, ETag만 보내서 같으면 유지, 다르면 다시 받기이다.
  • 캐시 제어 로직을 서버에서 완전히 관리한다.

 

이런식으로, ETag 필드를 HTTP 응답 헤더에 포함해서 보낸다.

브라우저에서 캐시 데이터의 유효 시간이 지나서 재요청을 할 때는 If-None-Match 필드를 요청 헤더에 포함시킨다.

서버는 이를 받고 본인이 가지고 있는 ETag와 동일하다면 앞서 말한 것과 마찬가지로, HTTP 바디를 제외한 304 Not ModifiedHTTP 헤더만 보내게 된다. 

[ If-Match 필드를 사용해서 요청 메세지를 보낼 때는, 서버는 ETag가 본인과 동일하다면 200 OK 를 전송하며 HTTP 바디를 제외한다. ]

 


캐시 제어 헤더

  • Cache-Control : max-age
    • 캐시 유효 시간, 초 단위
  • Cache-Control : no-cache
    • 데이터는 캐시해도 되지만, 항상 원 (origin) 서버에 검증하고 사용
  • Cache-Control : no-store
    • 데이터에 민감한 정보가 있으므로 저장하면 안됨

프록시 캐시

우리가 유튜브를 보면 알 수 있듯이, 해외에 있는 데이터도 우리는 빠른 속도로 읽어올 수 있다.

물리적으로 거리가 멀기 때문에, 한국에 있는 클라이언트들과 미국에 있는 서버 사이에 어떻게 빠른 데이터 전송이 가능할까?

이를 가능하게 만든 것이 프록시 캐시 이다.

 

미국에 있는 origin 서버에 직접 접근하기 때문에 오래 걸릴 수 밖에 없다.

 

미국 원 서버에 있는 데이터를 프록시 캐시 서버가 캐시 데이터로 받아와서 이를 우리에게 뿌려준다면?

이와 같이, 우리는 더 빠른 속도로 같은 데이터를 이용할 수 있는 것이다.

여기에서, 각각의 클라이언트는 private 캐시를 가지게 되고 이는 해당 사용자만을 위한 것임을 뜻한다. 

프록시 캐시 서버는 public 캐시를 가진다.

(프록시 캐시에 적용되는 캐시 유효 시간을 설정하는 필드는 Cache-Control: s-maxage 이다.)


캐시 무효화

캐시를 무효화시켜야하는 상황들이 있다 위에서 말했듯이 저장을 하면 안되는 데이터가 포함된 경우 등이 말이다.

이때 사용되는 확실한 캐시 무효화 응답이 아래와 같다.

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

no-cache, no-store은 위에서 설명하였고, must-revalidate에 대해서만 더 설명하겠다.

Cache-Control: must-revalidate

→ 캐시 만료 후 최초 조회시 원 서버에 검증해야 함, 원 서버 접근 실패시 반드시 오류가 발생 ( 504 Gateway Timeout )

 

no-cache VS must-revalidate

둘다, 캐시 데이터를 사용하는데 이를 사용할 때마다 원 서버에 검증하고 사용하라는 뜻인데 어떤 차이가 있을까?

no-cache 동작 원리

위의 그림과 같이 no-cache는 작동하게 된다.

그런데, 여기서 갑자기 프록시 캐시 서버와 원 서버의 네트워크가 단절되면 어떻게 될까?

결론부터 말하자면, 프록시 캐시 서버는 웹 브라우저로 200 OK의 응답을 보내게 된다.

원 서버와 데이터가 일치하는지 제대로 확인을 하지 않았음에도 불구하고, 프록시 캐시 서버는 에러를 내지 않으려고 오래된 데이터라도 보여주게 된다. 그렇기 때문에 이로 인해 혼선이 생길 가능성이 있다.

VS

must-revalidate

그와 반해, must-revalidate는 원 서버와 네트워크가 단절되면 504 Gateway Timeout 오류를 내보내게 된다.


정리

이번 게시글은 다른 게시글에 비해 말이 많았는데, 어려울 수 있는 내용과 헷갈릴 수 있는 내용을 최대한 풀어서 독자가 이해하기 쉽게 하려다 보니 그런 것 같다.

이렇게 해당 게시글을 마지막으로 HTTP 에 대한 게시글은 끝이 났다.

앞으로도 종종 복습을 하면서 더 새로운 내용이 있다면 추가하도록 하겠다.

728x90
반응형

'Http' 카테고리의 다른 글

HTTP Header(헤더)의 구조, 쿠키  (0) 2023.07.28
HTTP Status Code(상태 코드)  (0) 2023.07.26
Http Method 활용  (0) 2023.07.25
HTTP API, Method(메서드)  (0) 2023.07.22
HTTP  (0) 2023.06.23