• network
  • http
  • web

HTTP 메서드와 상태 코드: 멱등성, POST와 PUT의 차이

HTTP 메서드의 역할과 멱등성, POST·PUT·PATCH를 구분하는 기준, 헷갈리기 쉬운 상태 코드의 차이를 정리한다.

시리즈 · 네트워크9 / 12
  1. OSI 7 Layer와 계층별 역할, ARP
  2. IP 주소: IPv4와 IPv6, NAT, 체크섬
  3. 라우터: 경로 지정, 브로드캐스트 컨트롤, 라우팅과 스위칭
  4. DHCP 동작 방식과 UDP를 사용하는 이유
  5. IP의 한계와 TCP·UDP, 3-Way Handshake
  6. TCP 4-Way Handshake와 TIME_WAIT
  7. DNS 정리: 구조, 질의 방식, 레코드, 이중화와 위임
  8. 로드 밸런서: 구성 방식, 헬스 체크, L4와 L7
  9. HTTP 메서드와 상태 코드: 멱등성, POST와 PUT의 차이
  10. HTTP의 Stateless·Connectionless와 쿠키, 세션
  11. HTTP/1.1, HTTP/2, HTTP/3 비교
  12. 소켓과 포트, 그리고 웹소켓

HTTP

HTTP는 HTML 문서와 같은 리소스를 가져올 수 있게 해 주는 클라이언트-서버 프로토콜이다.

HTTP 메서드

요청 메서드는 주어진 리소스에 수행하길 원하는 행동을 나타낸다.

메서드 역할
GET 특정 리소스의 표시를 요청한다. 오직 데이터를 받기만 한다.
HEAD GET과 동일한 응답을 요구하지만, 응답 본문은 포함하지 않는다.
POST 특정 리소스에 엔티티를 제출한다. 서버의 상태 변화나 부수 효과를 일으킨다.
PUT 대상 리소스 전체를 요청 내용으로 덮어쓴다.
PATCH 리소스의 일부만 수정한다.
DELETE 특정 리소스를 삭제한다.
CONNECT 목적 리소스로 식별되는 서버로의 터널을 맺는다.
OPTIONS 목적 리소스의 통신 옵션을 설명한다.

멱등성

동일한 요청을 한 번 보내는 것과 여러 번 연속으로 보내는 것이 같은 효과를 내고 서버의 상태도 동일하게 남을 때, 해당 메서드가 멱등성을 가졌다고 한다.

  • GET, PUT, DELETE는 멱등하다.
  • POST는 호출할 때마다 요청된 데이터가 추가되므로 멱등하지 않다.
  • PATCH는 일부만 수정하는 “변화”를 명령할 수 있어서 구현에 따라 다르다.

GET과 POST의 차이

  • 목적: GET은 데이터를 받는 목적으로만 쓰인다.
  • Body: GET은 일반적으로 Body를 사용하지 않는다.
  • 멱등성: POST는 멱등성을 보장하지 않는다.

GET에도 Body를 실을 수 있는데 왜 지양하는가

스펙상 GET 요청에 Body를 싣는 것이 금지되어 있지는 않다. 그럼에도 이 방식을 지양하는 이유는 다음과 같다.

  • 캐시 가능성: GET 요청은 웹 브라우저 등에 의해 자주 캐시된다. GET 요청을 단순하고 예측 가능하게 유지해야 캐시를 쉽게 관리하고 조회할 수 있다.
  • 안전성: GET은 서버 상태를 바꾸지 않는 멱등한 조회 메서드라는 의미를 유지해야 한다.

POST와 PUT, PATCH

기존에 알고 있던 구분

POST와 PUT의 차이를 이렇게만 알고 있었다.

  • POST: Create
  • PUT: Update

틀린 말은 아니지만, 더 정확한 기준은 리소스의 URI를 누가 결정하는가이다.

  • POST: 클라이언트는 등록될 리소스의 URI를 모른다. 서버가 결정한다.
  • PUT: 클라이언트가 리소스의 URI를 직접 지정한다.

예시

유저 스키마가 다음과 같다고 하자.

  • id: Int (순차적으로 1씩 증가하며 저장됨)
  • name: String

POST /members

  • 유저를 생성한다.
  • 클라이언트는 생성될 유저가 어떤 id를 갖게 될지 모른다. 즉 등록될 리소스의 URI를 모르고, 서버가 결정한다.

PUT /members/{id}

  • 유저 정보를 수정한다.
  • 클라이언트가 대상 유저가 누구인지 이미 알고 있다. 리소스의 URI를 클라이언트가 알고 지정한다.

PUT과 PATCH

DB 수정이 일어나면 무조건 PUT을 사용해 왔는데 좋은 방법이 아니었다.

  • PUT: 기존 데이터를 통째로 덮어쓴다.
  • PATCH: 데이터의 일부만 수정한다.

부분 수정에는 PATCH를 쓰는 것이 맞다.

컨트롤 URI

모든 동작이 HTTP 메서드만으로 표현되면 좋겠지만, 실제로는 딱 맞아떨어지지 않는 경우가 많다. 그럴 때 나는 /members/delete/{id}처럼 써 왔는데, /members/{id}/delete처럼 리소스 식별을 해치지 않는 형태로 컨트롤 URI를 붙이는 편이 낫다.

상태 코드

2XX와 3XX 응답 중 무엇을 골라야 하는지는 아래 흐름도로 정리할 수 있다.

리다이렉트 여부, 메서드 변경 가능 여부, 일시적인지에 따라 2XX와 3XX 상태 코드를 고르는 흐름도

200 OK와 201 Created

  • 200 OK: 요청을 정상적으로 수행했음을 의미한다.
  • 201 Created: POST나 PUT으로 게시물 작성처럼 새로운 데이터를 서버에 쓰는 작업이 성공했을 때 반환한다. 200과 달리 응답의 Location 헤더에 생성된 리소스의 위치(예: /members/100)가 포함된다.

3XX 리다이렉션

301과 302는 리다이렉트할 때 요청 메서드가 GET으로 바뀌고 본문이 제거될 수 있다. 메서드와 본문을 유지해야 하면 307과 308을 사용한다.

코드 이름 지속성 메서드 의미
301 Moved Permanently 영구 GET으로 바뀔 수 있음 URL이 영구적으로 바뀌었다
302 Found 일시 GET으로 바뀔 수 있음 일시적으로 다른 URL로 이동한다
307 Temporary Redirect 일시 유지 클라이언트는 이후에도 원래 URL을 계속 시도해야 한다
308 Permanent Redirect 영구 유지 클라이언트와 검색 엔진은 URL이 바뀐 것으로 캐싱해 두어야 한다

401 Unauthorized와 403 Forbidden

  • 401 Unauthorized: 클라이언트가 인증되지 않았거나 유효한 인증 정보가 부족해 요청이 거부되었다. 누구인지 확인되지 않아 요청을 처리할 수 없는 상태다.
  • 403 Forbidden: 서버가 요청을 이해했지만 권한이 없어 거부했다. 즉 로그인은 되었지만 권한이 없는 무언가를 요구한 경우다.

Reference