이 사이트의 실습은 자바스크립트를 켜야 움직입니다. 아래는 같은 내용을 글로 적은 것입니다.
공부 › 네트워크 › HTTP
HTTP 캐시와 ETag
같은 파일을 또 받을 필요가 있을까
브라우저는 한 번 받은 응답을 보관해 두었다가 다시 씁니다. 서버가 응답 헤더로 "얼마 동안 그대로 써도 되는지"와 "내용의 버전 표시(ETag)"를 알려 주면, 브라우저는 요청을 아예 생략하거나 "바뀌었느냐"만 물어볼 수 있습니다.
실행으로 대조 · 시험 서버와 실제 브라우저로 확인
이 실습에 나오는 개념
- 조건부 요청과 ETag
- 클라이언트가 이미 가지고 있는 데이터가 여전히 최신인지 서버에 확인하는 요청 방식이다. ETag는 자원의 버전을 나타내는 식별 값으로, 클라이언트가 이 값을 요청에 실어 보내면 서버는 자원이 바뀌지 않은 경우 본문 없이 304 Not Modified로 응답한다. 같은 데이터를 다시 전송하지 않아 네트워크 사용을 줄인다.
- HTTP 상태 코드
- 서버가 요청을 처리한 결과를 나타내는 세 자리 숫자다. 2xx는 성공, 3xx는 다른 위치로의 이동(리다이렉션), 4xx는 클라이언트의 요청에 문제가 있음, 5xx는 서버 쪽 오류를 뜻한다. 200(성공), 201(생성됨), 400(잘못된 요청), 401(인증 필요), 403(권한 없음), 404(없음), 500(서버 오류)이 자주 쓰인다.
- 캐시
- 자주 사용하는 데이터나 계산 결과를 빠르게 접근할 수 있는 곳에 미리 저장해 두고 재사용하는 것이다. 원본(주로 데이터베이스)을 매번 조회하지 않아 응답이 빨라지고 원본의 부하가 줄어든다. 대신 원본이 바뀌었을 때 캐시의 값이 오래된 상태로 남는 문제를 관리해야 한다.
- CDN
- 전 세계 여러 지역에 배치된 서버에 콘텐츠의 복사본을 두고, 사용자와 가까운 서버가 응답하게 하는 네트워크다. 이미지, 영상, 스크립트 같은 정적 파일의 전송이 빨라지고 원본 서버로 가는 요청이 줄어든다.
이렇게 바꿔 보세요
- 처음 설정으로 — 유효 시간이 지난 뒤 다시 요청. 안 바뀌었으면 본문 없이 304만 옵니다.
- 유효 시간 안에 다시 열면 — 서버에 요청조차 보내지 않습니다.
- 내용이 바뀌었다면 — ETag가 달라 새 내용을 200으로 받습니다.
- 유효 시간 안인데 내용이 바뀌면 — 브라우저는 모르고 옛 내용을 씁니다.
- no-store — 저장하지 않으므로 매번 전부 다시 받습니다.
- no-cache — 저장은 하되 쓸 때마다 서버에 확인합니다.
처음 설정으로 실행하면
- 처음 여는 주소입니다. 브라우저에 저장된 것이 없으므로 서버에 요청합니다.
- 서버가 본문 200KB와 함께 캐시 지시를 내려 줍니다. 브라우저는 본문과 ETag(내용의 버전을 나타내는 표시)를 함께 보관합니다.
- 120초 뒤 같은 주소를 다시 엽니다. 유효 시간 60초가 지났습니다. 브라우저는 저장해 둔 것을 버리지 않고, "내가 가진 것은 v1인데 아직 그대로인가?"라고 묻습니다.
- 서버의 현재 ETag도 "v1"입니다. 바뀐 것이 없으므로 본문 없이 304만 응답합니다. 브라우저는 저장해 둔 본문을 그대로 씁니다. 유효 시간도 다시 시작합니다. 200KB를 다시 보내지 않았습니다.
실행 결과
- 304 응답은 본문이 없어 전송량이 거의 없습니다. 다만 요청과 응답의 왕복은 한 번 일어나고, 서버는 현재 ETag를 알기 위해 일을 해야 합니다.
코드
@GetMapping("/products/{id}")
ResponseEntity<Product> get(@PathVariable long id) {
Product p = productService.find(id);
return ResponseEntity.ok()
.cacheControl(CacheControl.maxAge(60, TimeUnit.SECONDS))
.eTag("\"v" + p.getVersion() + "\"") // 내용의 버전 표시
.body(p);
}
// 요청의 If-None-Match가 현재 ETag와 같으면
// 스프링이 본문 없이 304 Not Modified로 응답한다
이 모형의 전제
본문 크기 200KB는 예시입니다. 캐시 지시와 조건부 요청의 의미는 HTTP 캐시 표준(RFC 9111)과 조건부 요청 정의(RFC 9110)를 따랐습니다. ETag 대신 최종 수정 시각(Last-Modified / If-Modified-Since)으로도 같은 확인을 할 수 있습니다. 사용자가 새로 고침을 누르면 브라우저가 유효 시간과 무관하게 확인 요청을 보내기도 합니다. 로컬 시험 서버와 실제 브라우저(크로미움 기반)로 확인했습니다(유효 시간은 2초로 줄여 시험). 유효 시간 안의 재요청은 서버에 도착하지 않았고, 지난 뒤에는 If-None-Match가 붙어 304가 돌아왔으며, 내용이 바뀐 경우에는 200과 새 본문이 왔습니다. no-store는 두 번 모두 전체를 받았고, no-cache는 바로 다시 요청해도 조건부 요청이 나갔습니다. 유효 시간 안에 서버 내용이 바뀐 경우 브라우저는 옛 내용을 그대로 썼습니다.
앞 실습: 쿠키 · 다음 실습: 재시도와 멱등성