अपडेट किया गया 1 माह पहले
요청을 보냈습니다. 네트워크 타임아웃이 발생했습니다. 서버가 처리했을까요?
정말로 알 수 없습니다. 요청이 도착해서 성공했지만 응답만 유실되었을 수도 있습니다. 아니면 요청이 전송 중에 사라졌을 수도 있습니다. 네트워크는 요청이 성공했는지 알려주지 않습니다—응답을 받았는지 알려줄 뿐입니다. 이 둘은 같은 것이 아닙니다.
멱등성은 이 불확실성을 다루는 방법입니다.
멱등성의 의미
HTTP 메서드는 동일한 요청을 여러 번 보내도 한 번 보낸 것과 서버 측 결과가 동일할 때 멱등하다고 합니다.
DELETE는 멱등합니다. 리소스를 한 번 삭제하면 사라집니다. 열 번 더 삭제해도—여전히 사라져 있습니다. 응답은 다를 수 있지만 (처음에는 204 No Content, 이후에는 404 Not Found를 반환), 결과는 동일합니다: 리소스가 존재하지 않습니다.
POST는 일반적으로 멱등하지 않습니다. 폼을 세 번 제출하면 세 개의 리소스가 생성될 수 있습니다. 신용카드를 세 번 청구하면 고객에게 세 번 청구됩니다. 각 요청이 서버 상태를 새로운 방식으로 변경합니다.
멱등한 메서드
GET
리소스를 조회하는 것은 리소스를 변경하지 않습니다. 동일한 게시글을 백 번 요청해도—서버 상태는 변하지 않습니다.
주의: 잘못 설계된 API는 GET에 부작용을 끼워 넣습니다—조회수 카운터 증가, 특정 액션 트리거, 로깅 등. 이는 HTTP 명세를 위반하며, 프록시, 브라우저, 로드 밸런서가 안전하다고 가정하고 GET 요청을 재시도할 때 실제 문제를 야기합니다.
PUT
리소스를 특정 상태로 업데이트하는 것은 멱등합니다. 게시글 제목을 "Updated Title"로 한 번 설정하면 그 제목이 됩니다. 다시 설정해도—여전히 그 제목입니다.
DELETE
리소스를 제거하는 것은 멱등합니다. 첫 번째 요청 후 리소스는 사라집니다. 열 번째 요청 후에도 여전히 사라져 있습니다.
HEAD와 OPTIONS
HEAD는 아무것도 수정하지 않고 메타데이터를 조회합니다. OPTIONS는 서버가 지원하는 기능을 확인합니다. 둘 다 서버 상태를 변경하지 않습니다.
멱등하지 않은 메서드
POST
POST를 보낼 때마다 새로운 상태가 만들어질 수 있습니다:
이게 바로 중복 제출 문제입니다. 네트워크 타임아웃, 참을성 없는 사용자가 "제출" 버튼을 여러 번 클릭, 자동 재시도—이 모든 것이 의도치 않은 중복을 만들어냅니다.
PATCH
PATCH는 패치 형식에 따라 멱등할 수도 있고 그렇지 않을 수도 있습니다.
멱등함 (절대값 설정):
멱등하지 않음 (상대적 변경):
JSON Merge Patch (RFC 7396)는 멱등합니다. JSON Patch (RFC 6902)는 사용하는 작업에 따라 멱등하지 않을 수 있습니다.
멱등성이 중요한 이유
안전한 재시도
멱등한 메서드에서는 자유롭게 재시도할 수 있습니다:
GET은 멱등합니다. 재시도해도 아무 문제가 없습니다.
POST에서는 재시도가 위험합니다:
로드 밸런서의 자동 재시도
백엔드 서버가 타임아웃될 때, 로드 밸런서는 멱등한 요청을 다른 서버에 재시도합니다:
특별한 설정 없이는 POST를 재시도하지 않습니다. 위험하다는 걸 알기 때문입니다.
브라우저가 사용자를 보호하는 방법
폼을 제출한 후 페이지를 새로고침하면 이런 메시지를 보게 됩니다:
브라우저는 POST가 멱등하지 않다는 것을 알고 있습니다. 반복하기 전에 경고를 보냅니다.
캐싱의 동작 원리
멱등한 메서드만 안전하게 캐시할 수 있습니다. 요청이 서버 상태를 변경한다면, 캐시된 응답은 거짓말이 됩니다.
GET 응답은 기본적으로 캐시됩니다. POST 응답은 그렇지 않습니다.
POST를 멱등하게 만들기
POST는 재시도가 필요한 경우가 많기 때문에, 멱등성을 추가하는 몇 가지 패턴이 있습니다:
멱등성 키
클라이언트는 각 논리적 작업에 고유한 키를 생성합니다:
서버는 키를 추적합니다. 같은 키가 두 번 오면? 원래 결과를 그대로 반환합니다:
이제 재시도가 안전해집니다.
클라이언트 지정 ID
클라이언트가 직접 ID를 제공하도록 합니다:
특정 URL에 대한 PUT은 멱등합니다. 주문이 이미 존재하면 업데이트하고, 없으면 새로 만듭니다. 재시도해도 동일한 주문 하나만 남습니다.
일회용 토큰
폼에 토큰을 숨겨둡니다:
서버가 검증하고 즉시 무효화합니다:
중복 제출은 실패합니다.
RESTful 설계
메서드를 의미에 맞게 사용하세요:
멱등한 작업 → PUT 또는 DELETE
- 리소스를 특정 상태로 설정: PUT
- 리소스 제거: DELETE
멱등하지 않은 작업 → POST
- 서버가 ID를 생성하며 만들기: POST
- 반복되어서는 안 되는 작업: POST
멱등합니다. 상태를 "active"로 열 번 설정해도 결과는 active 상태 하나입니다.
멱등하지 않습니다. 두 번 보내면 메시지가 두 개 전송됩니다.
멱등성 테스트
멱등한 메서드가 실제로 멱등한지 검증하세요:
흔한 실수
GET에 부작용 추가: GET 핸들러에서 상태를 변경하지 마세요. 프록시와 브라우저는 묻지도 않고 GET 요청을 재시도합니다.
POST 무분별한 재시도: 멱등성 키나 토큰 없이 재시도하면 중복이 발생합니다.
PATCH가 항상 멱등하다고 가정: 패치 형식에 따라 다릅니다. 증분 연산은 멱등하지 않습니다.
HTTP 메서드 멱등성에 관한 자주 묻는 질문
DELETE가 멱등하다면 왜 이후 요청에서 404를 반환하나요?
멱등성은 응답 코드가 아닌 서버 측 효과를 말합니다. DELETE 이후 리소스는 존재하지 않습니다—한 번 삭제했든 열 번 삭제했든 결과는 같습니다. 404는 단순히 "여기 없습니다"를 뜻하며, 이것이 바로 원하던 상태입니다. 효과는 동일하고, 응답 코드만 다를 뿐입니다.
타임아웃된 모든 요청을 안전하게 재시도할 수 있나요?
멱등한 요청(GET, PUT, DELETE, HEAD, OPTIONS)만 가능합니다. POST의 경우 멱등성 키나 유사한 보호 수단이 필요합니다. 없으면 타임아웃된 POST를 재시도했을 때 중복이 발생할 수 있습니다—원래 요청이 성공했는지 알 방법이 없기 때문입니다.
멱등한 메서드와 안전한 메서드의 차이는 무엇인가요?
안전한 메서드(GET, HEAD, OPTIONS)는 서버 상태를 전혀 수정하지 않습니다. 멱등한 메서드는 상태를 수정할 수 있지만, 반복해도 결과가 달라지지 않습니다. DELETE는 멱등하지만 안전하지는 않습니다—상태를 수정하지만, 두 번 실행해도 한 번 실행한 것과 효과가 같습니다.
멱등성 키를 얼마나 오래 저장해야 하나요?
재시도 윈도우와 네트워크 지연을 충분히 커버할 만큼—사용 사례에 따라 보통 1~24시간입니다. Stripe는 24시간을 사용합니다. 대부분의 API에서는 몇 시간이면 충분합니다. 너무 짧으면 재시도가 빠져나갈 수 있고, 너무 길면 저장 공간을 낭비하게 됩니다.
क्या यह पृष्ठ सहायक था?