가능세계
[Network] 캐시와 조건부 요청(Cache & Conditional request) 정리하기 본문
네트워크를 통해 리소스를 가져오는 과정은 느리며 비용이 많이 듭니다. 동일한 이미지를 반복해서 요청하면 데이터를 다시 다운로드해야 하므로 웹 사이트의 로딩 속도와 사용자 경험이 저하될 수 있습니다.
이처럼 불필요한 네트워크 요청을 어떻게 피할 수 있을까요?
여기서 HTTP 캐시라는 개념이 등장합니다.
1. 캐시란 무엇인가요?
1-1. 캐시(Cache)와 캐싱(Caching)
캐시(Cache)는 자주 사용되는 데이터를 임시로 복사해 두는 저장소를 의미합니다.
그리고 데이터를 캐시에 저장하는 행위를 캐싱
(Caching)이라고 합니다.
캐싱은 주어진 리소스를 저장하고 재사용하여 보다 빠르게 액세스 할 수 있도록 하는 프로세스라고 할 수 있습니다.
1-2. HTTP 캐시
네트워크를 사용하는 웹 환경에도 캐시 개념을 적용할 수 있습니다.
웹 캐시가 자신의 저장소 내에 요청된 리소스를 가지고 있다면, 원래의 서버로부터 리소스를 다시 다운로드하는 대신 리소스의 복사본을 반환합니다.
이로써 비싼 네트워크 사용량을 줄일 수 있으며, 브라우저 로딩 속도가 향상되어 사용자 경험을 최적화할 수 있습니다.
2. HTTP 캐싱은 어떻게 작동하나요?
가장 기본적으로 캐싱 프로세스는 다음과 같이 작동합니다.
- 웹 사이트는 원본 서버에 리소스를 요청합니다.
- 시스템은 캐시를 확인하여 해당 리소스의 복사본이 있는지 여부를 판단합니다.
- 리소스가 캐시에 저장되어 있다면, 리소스는 캐시에서 제공됩니다.
- 리소스가 캐시에 없는 경우, 파일은 원본 소스에서 제공됩니다.
- 캐시 유효 시간이 만료되거나 캐시가 지워질 때까지 리소스는 계속해서 캐시에서 제공됩니다.
3. 검증 헤더와 조건부 요청
만약 캐시 만료 후에도 서버에서 데이터를 변경하지 않았다면, 데이터를 전송하는 대신에 저장해둔 캐시를 재사용할 수 있습니다.
단, 클라이언트의 데이터와 서버의 데이터가 같다는 사실을 확인하는 방법이 필요합니다. 이런 과정을 캐시 유효성 검증(Validation) 및 조건부 요청(Conditional request)이라고 합니다.
캐시의 리소스가 오래되면 클라이언트는 리소스가 여전히 유효한지 확인하기 위해 조건부 요청을 보낼 수 있습니다.
검증 헤더로 캐시 데이터와 서버 데이터가 일치하는지 여부를 확인하며, 검증 헤더는 최종 수정 시간을 나타내는 Last-Modified
와, 특정 리소스 버전을 나타내는 ETag
로 나뉘어집니다.
3-1. If-Modified-Since는 Last-Modified를 사용합니다
1. 최초 요청
GET /index.html HTTP/1.1
Host: example.com
2. 최초 요청 시 응답
HTTP/1.1 200 OK
Content-Type: text/html
Last-Modified: Sat, 03 Sep 2022 00:00:00 GMT
Content-Length: 157
<message body contains resource>
웹 브라우저는 Last-Modified
헤더와 함께 응답 결과를 캐시에 저장합니다.
Last-Modified 헤더는 데이터가 마지막으로 수정된 시간을 나타냅니다.
3. 두 번째 요청
GET /index.html HTTP/1.1
Host: example.com
If-Modified-Since: Sat, 03 Sep 2022 00:00:00 GMT
캐시에 저장해 둔 Last-Modified
값, 즉 캐시의 최종 수정일을 If-Modified-Since라는 HTTP 요청 헤더에 넣어 서버에 요청을 보냅니다.
4. 리소스가 변경되지 않았을 경우 두 번째 응답
HTTP/1.1 304 Not Modified
Last-Modified: Sat, 03 Sep 2022 00:00:00 GMT
클라이언트에서 보내는 If-Modified-Since
와 서버의 Last-Modified
를 비교하여 데이터가 갱신된 부분이 없는지 판단합니다.
만약 조건부 요청을 보냈는데 원본 리소스에 아무런 변경이 없었다면, 서버는 304 Not Modified
라는 상태 코드로 응답합니다.
데이터에 수정된 것이 없으므로 이 응답에는 바디를 제외한 헤더 메타 정보만 전송됩니다.
클라이언트는 서버가 보낸 응답 헤더 정보로 캐시의 메타 정보를 갱신하고, 캐시에 저장되어 있는 데이터를 재활용합니다.
이로써 네트워크 부하가 줄어들고, 트래픽을 아낄 수 있습니다.
5. 세 번째 요청
GET /index.html HTTP/1.1
Host: example.com
If-Modified-Since: Sat, 03 Sep 2022 00:00:00 GMT
6. 리소스가 변경되었을 경우 세 번째 응답
HTTP/1.1 200 OK
Content-Type: text/html
Last-Modified: Sun, 04 Sep 2022 00:00:00 GMT
Content-Length: 250
<message body contains resource>
3-2. Last-Modified와 If-Modified-Since의 한계점
Last-Modified
와 If-Modified-Since
의 사용에는 단점이 있습니다. ms
단위로 캐시 조정이 불가능하며, 날짜 기반의 정해진 로직을 사용해야 한다는 것입니다.
데이터를 수정하면 파일의 날짜가 갱신된다는 것을 생각해 봅시다.
만약 데이터를 A->B->A로 수정한다면 어떨까요? 이 경우 실제 콘텐츠 자체는 수정되지 않았지만, 날짜가 변경되었으므로 전체 데이터를 다시 다운로드 받아야 합니다.
혹은 스페이스나 주석처럼 크게 영향이 없는 경우에는 캐시를 유지하고 싶을 수도 있습니다.
이처럼 Last-Modified
와 If-Modified-Since
는 서버에서 별도의 캐시 로직을 관리하고 싶은 경우, 사용이 적합하지 않습니다.
이러한 한계점에 대응하여 서버에서 완전하게 캐시 메커니즘을 컨트롤할 수 있는 방법이 있습니다. 바로 Etag
입니다.
3-3. If-None-Match는 ETag를 사용합니다
ETag(Entity Tag)는 캐시용 데이터에 대한 임의의 식별자입니다.
예로는 ETag: "v1.0"
, ETag: "a2jiodwjekjl3"
가 있습니다.
데이터가 갱신되면 Hash
를 재생성해 이 이름을 변경합니다. ETag가 같으면 캐시를 유지하고, 다르면 전체 데이터를 다시 받도록 합니다.
클라이언트는 캐시 메커니즘을 모른 채 단순히 ETag 값을 서버에 제공하면 되므로, 서버에서 캐시 제어 로직을 완전히 관리하게 됩니다.
1. 최초 요청
GET /index.html HTTP/1.1
Host: example.com
2. 최초 요청 시 응답
HTTP/1.1 200 OK
Content-Type: text/html
ETag: "abcdefg"
Content-Length: 157
<message body contains resource>
웹 브라우저는 ETag
헤더와 함께 응답 결과를 캐시에 저장합니다.
3. 두 번째 요청
GET /index.html HTTP/1.1
Host: example.com
If-None-Match: "abcdefg"
이후 캐시 시간이 초과되어 리소스에 대한 재요청 시 If-None-Match
헤더에 저장해 둔 ETag 값을 넣어서 보냅니다.
4. 리소스가 변경되지 않았을 경우 두 번째 응답
HTTP/1.1 304 Not Modified
ETag: "abcdefg"
원본 리소스가 변경되지 않아 ETag 값이 같으면, 서버는 메시지 바디를 제외하고, 304 Not Modified
로 응답합니다.
클라이언트는 내부적으로 캐시를 갱신하고, 캐시에 저장되어 있는 데이터를 재활용합니다.
5. 세 번째 요청
GET /index.html HTTP/1.1
Host: example.com
If-None-Match: "abcdefg"
6. 리소스가 변경되었을 경우 세 번째 응답
HTTP/1.1 200 OK
Content-Type: text/html
ETag: "hijklmn"
Content-Length: 500
<message body contains resource>
참고
'Blog > Network' 카테고리의 다른 글
[Network] 프록시 캐시(Proxy Cache)란 무엇인가요? (0) | 2023.09.11 |
---|---|
[Network] 캐시 제어 헤더(Cache-Control Headers)란 무엇인가요? (0) | 2023.09.11 |
[Network] HTTP 헤더 살펴보기 - 쿠키(HTTP Cookies) (0) | 2023.09.11 |
[Network] HTTP 헤더 살펴보기 - 인증(Authentication) (0) | 2023.09.11 |
[Network] HTTP 헤더 살펴보기 - 콘텐츠 협상(Contents Negotiation) (0) | 2023.09.11 |