Conditional GET with ETag

이전에 받은 ETag를 `If-None-Match`로 되돌려 보내, 리소스가 바뀌지 않았으면 304 Not Modified만 받아 대역폭을 아끼는 조건부 GET 레시피입니다.

개요

이전에 받은 ETag를 `If-None-Match`로 되돌려 보내, 리소스가 바뀌지 않았으면 304 Not Modified만 받아 대역폭을 아끼는 조건부 GET 레시피입니다.

코드로 보기

# 1) first request returns an ETag
curl -i https://api.example.com/config
#    ETag: "a1b2c3"

# 2) revalidate: send it back, get 304 if unchanged
curl -i https://api.example.com/config \
  -H 'If-None-Match: "a1b2c3"'
const first = await fetch('/config');
const etag = first.headers.get('ETag');

const next = await fetch('/config', {
  headers: { 'If-None-Match': etag }
});
if (next.status === 304) {
  // not modified — reuse cached body
}
import requests

r1 = requests.get('https://api.example.com/config')
etag = r1.headers['ETag']

r2 = requests.get('https://api.example.com/config',
                  headers={'If-None-Match': etag})
print(r2.status_code)  # 304 if unchanged (r2.content is empty)

설명

첫 응답의 `ETag`(리소스 버전 식별자)를 저장해 두었다가, 다음 요청에 `If-None-Match: "<etag>"`로 보냅니다. 리소스가 그대로면 서버는 본문 없이 304를 반환하고, 클라이언트는 캐시에 둔 이전 본문을 재사용합니다. 바뀌었으면 200과 새 본문·새 ETag가 옵니다.

ETag는 `"..."`로 감싼 강한(strong) 검증자와 `W/"..."`로 시작하는 약한(weak) 검증자가 있습니다. 약한 ETag는 의미상 동등하면 같은 것으로 취급해 바이트 단위 일치가 필요한 Range 요청 등에는 부적합합니다.

시간 기반 대안으로 `Last-Modified` + `If-Modified-Since`가 있지만 초 단위 해상도라 정밀도가 낮습니다. 조건부 요청은 쓰기(PUT/DELETE)에서는 `If-Match`로 낙관적 잠금에 쓰이며, 조건 불일치 시 412 Precondition Failed가 납니다.

관련 헤더

관련 상태코드