클라이언트가 읽을 때 받은 ETag를 If-Match 조건으로 쓰면 서버는 현재 표현이 그 태그와 강하게 일치할 때만 변경을 수행합니다. 중간에 자원이 바뀌었다면 조건은 거짓이 되고 서버는 변경을 수행하지 않아야 합니다.
사전조건이 거짓이면 서버는 보통 412 Precondition Failed로 알릴 수 있습니다. 응답이 데이터를 자동 병합하거나 최신값으로 다시 저장해 주는 것은 아닙니다.
읽은 뒤 바뀐 자원인지 조건으로 확인합니다
‘읽고-수정하고-저장하기’ 흐름에서는 두 사람이 같은 시점의 값을 보고 작업할 수 있습니다. 첫 번째 저장 뒤 두 번째 저장이 아무 검사 없이 실행되면, 두 번째 사용자는 첫 번째 변경이 반영된 사실을 모른 채 자신의 오래된 화면 값으로 덮어쓸 수 있습니다. 이를 잃어버린 갱신(lost update) 문제라고 부릅니다. HTTP의 If-Match는 요청을 처리하기 전에 현재 표현의 엔터티 태그가 조건과 일치하는지 검사하도록 합니다. RFC 9110 §13.1.1은 If-Match에 강한 비교를 사용하며, 대상 자원이 바뀌었는지 확인해 상태 변경 요청이 충돌을 일으키지 않게 하는 용도를 설명합니다.
두 번째 저장이 오래된 ETag를 제시합니다
계정 설정의 현재 표현을 v4라는 강한 ETag로 읽었다고 가정하겠습니다. 사용자 A가 먼저 이름을 바꾸고 저장해 서버의 현재 태그가 v5가 됩니다. 사용자 B의 화면은 여전히 v4를 기준으로 수정한 상태입니다. B가 저장할 때 If-Match에 자신이 읽은 v4를 넣으면 서버는 현재 태그 v5와 비교합니다. 일치하지 않으므로 B의 조건부 변경은 수행되지 않아야 합니다. 태그 문자열은 설명 편의를 위한 창작 값입니다.
GET /settings/42 HTTP/1.1
HTTP/1.1 200 OK
ETag: "v4"
PUT /settings/42 HTTP/1.1
If-Match: "v4"
Content-Type: application/json
{"name":"지우","digest":true}
HTTP/1.1 412 Precondition Failed| 시점 | 현재 서버 태그 | 요청 If-Match | 결과 |
|---|---|---|---|
| B가 읽은 직후 | "v4" | 아직 없음 | 읽은 표현 기준 확보 |
| A의 저장 이후 | "v5" | 아직 없음 | 서버 표현 변경 |
| B가 저장 | "v5" | "v4" | 불일치, 조건 실패 |
If-Match는 ‘내가 본 버전과 아직 같은가?’를 확인하는 문턱입니다. 요청에 조건을 붙였다는 사실만으로 충돌 처리가 끝나는 것은 아닙니다. 서버가 현재 태그를 올바르게 발급하고, 변경 시점에 조건을 검사해야 합니다. 또한 약한 엔터티 태그(W/ 접두어)는 If-Match의 강한 비교를 만족하지 않습니다. 태그를 단순한 숫자로 직접 증가시키는 구현이 아니라 서버가 표현 검증에 맞게 제공한 값을 그대로 보내야 합니다.
조건 실패 뒤에는 최신 상태를 다시 읽습니다
- 자원을 GET으로 읽고 응답의 ETag를 보관합니다.
- 사용자가 수정하는 동안 서버 상태는 달라질 수 있음을 고려합니다.
- 변경 요청에 보관한 태그를 If-Match로 보냅니다.
- 성공 응답이면 저장 결과와 새 ETag를 화면 상태에 반영합니다.
- 412 응답이면 최신 자원을 다시 읽고 차이를 보여 준 뒤 사용자 선택에 따라 다시 편집합니다.
RFC 9110 §15.5.13은 요청의 사전조건이 거짓일 때 412 Precondition Failed 상태를 설명합니다. 실제 응답 정책은 서버가 요청 조건을 처리하는 위치나 다른 오류 조건에 따라 세부적으로 달라질 수 있으므로 API 문서를 함께 확인해야 합니다. 중요한 학습 포인트는 조건 실패가 오래된 변경을 그대로 적용하지 않도록 막는다는 것입니다. 클라이언트는 최신 표현을 다시 받아 사용자의 변경과 비교해야 합니다.
412를 자동 병합이나 재시도 허가로 오해하지 않습니다
412는 ‘다른 사용자의 변경을 서버가 알아서 합쳤다’는 뜻이 아닙니다. 예를 들어 B가 digest 설정을 바꾸는 사이 A는 name을 변경했을 수 있습니다. 두 필드가 독립적이라면 화면에서 최신 이름을 보존하고 알림 설정 변경만 재적용하는 정책을 만들 수 있습니다. 하지만 같은 필드를 함께 바꿨다면 어느 쪽이 맞는지 사용자가 결정해야 할 수 있습니다. 무조건 최신 ETag를 붙여 같은 오래된 본문을 재전송하면, 조건 검사는 통과하더라도 A의 값을 다시 덮어쓸 수 있습니다.
또한 If-Match는 조건부 요청의 비교를 위한 헤더이지 자원 병합 프로토콜이 아닙니다. ‘412가 오면 자동으로 태그를 갱신하고 재시도’하는 코드는 충돌의 본질을 숨깁니다. 시스템은 재조회, 차이 비교, 사용자 선택 또는 안전하게 정의된 병합 규칙을 거쳐 새 요청을 만들어야 합니다. 멱등성과 재시도 가능성도 별도 고려 사항입니다. 시험 문제에서 상황을 읽을 때는 먼저 저장 시점의 버전 조건을 비교하고, 실패 후의 대응을 서버 자동 처리와 클라이언트 선택으로 구분하세요.
정답을 가리고 확인해 보세요
이 글을 위해 만든 학습 예시이며 공식 기출문제나 판매 카드의 인용이 아닙니다.
현재 강한 ETag가 v5인데 요청의 If-Match가 v4라면 사전조건은 참인가요? 일반적인 조건 실패 응답의 의미를 설명하세요.
정답과 해설 확인
강한 비교에서 일치하지 않으므로 조건은 거짓입니다. 서버는 해당 변경을 수행하지 않아야 하며 412 Precondition Failed로 알릴 수 있습니다.RFC 9110 §13.1.1의 If-Match는 강한 비교를 사용하고, 이미 바뀐 표현에 대한 상태 변경 충돌을 방지하는 데 쓰입니다. §15.5.13은 사전조건 실패 상태를 설명합니다. 412는 자동 병합을 의미하지 않습니다.