1. Библиотека
  2. HTTP와 웹
  3. HTTP 메서드

Обновено преди 1 месец

브라우저가 "이 양식을 다시 제출하시겠습니까?"라고 물을 때, 그건 단순히 귀찮게 구는 게 아닙니다. 원래 요청이 같은 작업을 두 번 했을 때 어떤 일이 일어날지에 대해 아무런 약속도 하지 않았기 때문에 묻는 겁니다. 카드가 다시 결제될 수도 있고, 주문이 중복으로 생성될 수도 있습니다. 브라우저는 알 수 없습니다—그리고 그 불확실성은 사용된 HTTP 메서드에 내재되어 있습니다.

HTTP 메서드는 결과에 대한 약속입니다. 요청이 이루어졌을 때 어떤 일이 일어날지에 대한 클라이언트와 서버 사이의 계약입니다. GET은 오직 조회만 하겠다고 약속합니다. POST는 무언가가 변경될 것임을 경고합니다. 웹의 전체 구조—캐싱, 재시도, 프리패칭, 그 새로고침 경고—는 이 약속들이 지켜지는 것에 달려 있습니다.

GET의 약속

GET은 말합니다: "나는 오직 볼 것입니다. 이 요청으로 인해 아무것도 변경되지 않을 것입니다."

URL을 입력하거나 링크를 클릭하면 브라우저는 GET 요청을 보냅니다. 서버는 아무것도 수정하지 않고 데이터—웹 페이지, 이미지, JSON—를 반환합니다. 이 약속이 웹을 빠르고 안정적으로 만드는 모든 것을 가능하게 합니다:

  • 캐싱이 작동합니다: 같은 요청을 다시 보내도 응답이 달라지지 않기 때문입니다
  • 프리패칭이 작동합니다: 링크를 미리 불러와도 원치 않는 동작이 일어나지 않기 때문입니다
  • 북마크가 작동합니다: URL 하나에 요청을 반복하는 데 필요한 모든 정보가 담겨 있기 때문입니다
  • 뒤로 가기 버튼이 작동합니다: 다시 방문해도 실수로 무언가를 다시 제출하지 않기 때문입니다

GET 요청은 URL에 매개변수를 포함할 수 있지만(?search=query&page=2), 그 매개변수는 어디까지나 조회 대상을 필터링하거나 지정하는 데만 써야 하며, 절대로 데이터 변경을 일으켜서는 안 됩니다.

GET의 약속을 어기는 것—데이터를 수정하는 GET 요청을 만드는 것—은 웹 개발에서 가장 위험한 실수 중 하나입니다. 한때 Google의 웹 크롤러가 GET으로 구현된 "삭제" 링크를 따라가는 바람에 한 회사를 파산시킨 적이 있습니다.

POST의 경고

POST는 말합니다: "무언가가 변경될 것입니다. 이것을 두 번 하면 어떻게 되는지 보장하지 않습니다."

양식을 제출하거나, 파일을 업로드하거나, 계정을 만들 때 POST 요청을 보냅니다. 데이터는 URL이 아닌 요청 본문에 담기며, 서버는 일반적으로 무언가를 생성하거나 처리하거나 특정 동작을 실행합니다.

POST는 반복에 대한 보장을 하지 않습니다. 결제 양식을 두 번 제출하면? 두 번 결제될 수도 있습니다. 계정을 두 번 만들면? 중복 레코드가 생길 수도 있습니다. 이것이 바로:

  • 브라우저가 POST 결과를 새로고침하기 전에 경고를 띄우는 이유입니다
  • 결제 후 뒤로 가기 버튼이 위험하게 느껴지는 이유입니다
  • API 클라이언트에 POST 요청을 위한 명시적인 재시도 로직이 필요한 이유입니다

POST는 솔직한 메서드입니다. 행동에는 결과가 따르며, 그 결과는 되돌릴 수 없거나 반복할 수 없을 수도 있다는 것을 인정합니다.

PUT: 완전한 교체

PUT은 말합니다: "이것이 이 리소스의 모습이어야 합니다. 기존 내용을 모두 이것으로 교체하세요."

무언가를 생성하거나 실행하는 POST와 달리, PUT은 교체합니다. 서버가 무엇이 달라졌는지 파악하게 만드는 게 아니라, 변경되지 않은 필드까지 포함해 완전한 새 상태를 직접 건네는 겁니다. PUT으로 사용자 프로필을 업데이트하면 모든 필드를 함께 보냅니다.

PUT은 강력한 약속을 합니다: 두 번 해도 한 번과 결과가 같습니다. 첫 번째 요청이 성공했다면 두 번째 요청은 같은 상태를 다시 확인할 뿐입니다. 첫 번째 요청이 원인 불명으로 실패했어도 안전하게 재시도할 수 있습니다. 이 속성—멱등성—은 신뢰할 수 있는 시스템에서 PUT을 매우 유용하게 만듭니다.

PATCH: 부분 수정

PATCH는 말합니다: "이 특정한 부분만 변경하세요."

PUT이 전체 리소스를 보내는 반면, PATCH는 변경 사항만 보냅니다. 이름, 전화번호, 설정은 건드리지 않고 이메일 주소만 업데이트합니다. 대용량 리소스에 효율적이며, 클라이언트가 모든 필드에 접근할 수 없을 때도 실용적입니다.

PATCH의 약속은 PUT보다 약합니다. PATCH를 반복 실행하는 것이 안전한지는 패치의 내용에 따라 달라집니다. "이메일을 X로 설정"은 반복해도 안전합니다. "카운터를 1 증가"는 그렇지 않습니다. 메서드 자체는 어떤 보장도 하지 않습니다.

DELETE: 삭제

DELETE는 말합니다: "이 리소스를 제거하세요."

/api/users/123에 DELETE를 보내면 해당 사용자가 삭제됩니다. 이후 GET 요청은 404 Not Found를 반환합니다. 간단합니다.

PUT처럼 DELETE도 멱등성을 가집니다. 두 번 삭제해도? 여전히 삭제된 상태입니다. 덕분에 네트워크 오류로 첫 번째 요청이 성공했는지 불확실할 때도 DELETE를 안전하게 재시도할 수 있습니다.

많은 시스템이 "소프트 삭제"를 구현합니다—리소스를 실제로 제거하는 대신 삭제됨으로 표시해 복구나 감사 목적으로 데이터를 보존합니다. 하지만 클라이언트 입장에서는 리소스가 사라진 것입니다.

HEAD와 OPTIONS: 메타데이터 메서드

HEAD는 말합니다: "리소스를 보내지 말고 이 리소스에 대한 정보만 알려주세요."

HEAD는 본문 없는 GET입니다. 파일이 존재하는지, 언제 수정되었는지, 크기가 얼마인지 확인합니다—다운로드 없이. 모니터링 시스템은 전체 페이지를 전송하지 않고도 서버가 응답하는지 확인하기 위해 HEAD를 사용합니다.

OPTIONS는 말합니다: "여기서 무엇을 할 수 있나요?"

OPTIONS는 서버에게 어떤 메서드가 허용되는지 묻습니다. 브라우저는 특정 교차 출처 요청 전에 자동으로 OPTIONS를 "프리플라이트" 확인으로 전송합니다—실제 요청을 시도하기 전에 허가를 구하는 것입니다.

안전 메서드: 서버 상태를 변경하지 않겠다는 약속

GET, HEAD, OPTIONS는 안전 메서드입니다. 서버 상태를 수정하지 않겠다고 약속합니다. 이 약속 덕분에 가능해지는 것들이 있습니다:

  • 프록시와 CDN의 적극적인 캐싱
  • 다음에 무엇을 클릭할지 미리 예측해 불러오는 브라우저의 프리패칭
  • 두려움 없이 사이트를 탐색하는 웹 크롤러
  • 중복을 걱정하지 않는 재시도 로직

POST, PUT, PATCH, DELETE는 비안전 메서드입니다. 무언가를 변경할 수 있습니다. 서버는 이것들을 신중하게 인증해야 하고, 클라이언트는 부주의하게 반복 실행해서는 안 됩니다.

멱등 메서드: 반복 실행에 관한 약속

GET, HEAD, OPTIONS, PUT, DELETE는 멱등 메서드입니다. 한 번 실행하나 두 번 실행하나 결과가 같습니다. 이 약속 덕분에 가능해지는 것들이 있습니다:

  • 네트워크 오류 발생 시 자동 재시도
  • 요청을 정상 서버로 다시 전달할 수 있는 로드 밸런서
  • 요청 성공 여부를 별도로 추적하지 않아도 되는 클라이언트

POST는 명시적으로 비멱등 메서드입니다. 메서드 자체가 경고합니다: "두 번 실행하면 어떻게 될지 보장할 수 없습니다." PATCH는 기술적으로 비멱등이지만, 많은 구현에서 패치를 반복해도 안전하게 설계합니다.

RESTful 관례: 언어로서의 메서드

REST API는 HTTP 메서드를 활용해 예측 가능한 인터페이스를 만듭니다:

동작메서드URL의미
목록 조회GET/users모든 사용자 표시
단건 조회GET/users/123이 사용자 표시
생성POST/users새 사용자 만들기
교체PUT/users/123이 사용자 전체 교체
수정PATCH/users/123이 사용자 부분 수정
삭제DELETE/users/123이 사용자 제거

이 패턴을 익히고 나면 API가 스스로를 설명하기 시작합니다. 메서드는 어떤 종류의 동작인지 알려주고, URL은 어떤 리소스인지 알려줍니다. 그 조합이 무슨 일이 일어날지 말해줍니다.

웹을 하나로 묶는 계약

HTTP 메서드는 임의로 붙인 이름표가 아닙니다. 전체 웹이 의존하는 약속입니다.

GET이 오직 조회만 하겠다는 약속 덕분에 캐싱이 작동하고, 프리패칭이 안전하고, 뒤로 가기 버튼이 실수로 주문을 다시 제출하는 일이 없습니다. POST의 솔직한 경고 덕분에 브라우저가 결제 페이지를 새로고침하기 전에 사용자를 멈춰 세웁니다. PUT과 DELETE의 멱등성 덕분에 분산 시스템이 실패한 요청을 두려움 없이 재시도할 수 있습니다.

이 약속들이 지켜지면 웹은 원활하게 돌아갑니다. 이것들이 깨지면—GET이 무언가를 삭제하거나, POST가 안전하게 재시도해도 된다고 가정하면—디버그하기 어렵고 때로는 되돌릴 수 없는 방식으로 문제가 터집니다.

메서드는 단순합니다. 그것들이 담고 있는 약속이 중요합니다.

HTTP 메서드에 관한 자주 묻는 질문

브라우저 폼이 GET과 POST만 지원하고 PUT이나 DELETE는 왜 지원하지 않나요?

HTML 폼은 REST 관례가 대중화되기 전에 설계되었습니다. form 요소는 메서드 값으로 GET과 POST만 지원합니다. 현대 웹 애플리케이션은 fetch나 XMLHttpRequest를 통해 JavaScript로 PUT, PATCH, DELETE 요청을 직접 보내거나, 서버가 해석하는 _method=DELETE 같은 숨겨진 필드를 포함하는 방식으로 이를 해결합니다.

GET 요청에 본문이 있을 수 있나요?

기술적으로는 가능하지만, 좋은 생각이 아닙니다. HTTP 명세가 이를 금지하지는 않지만, 서버는 GET 요청 본문을 무시해야 한다고 명시합니다. 많은 프록시, 캐시, 도구들이 이를 제거하거나 잘못 처리합니다. 복잡한 데이터를 보내야 한다면, 변형(mutation)이 아닌 조회(query)임을 명확히 표시한 POST를 사용하세요.

DELETE에서 200 OK와 204 No Content의 차이는 무엇인가요?

둘 다 성공을 나타냅니다. 200 OK는 일반적으로 응답 본문을 포함합니다(삭제된 리소스의 최종 상태나 확인 메시지 등). 204 No Content는 "성공했으며, 더 이상 할 말이 없습니다"—본문이 전혀 없습니다. DELETE의 경우 더 이상 존재하지 않는 것에 대해 의미 있게 반환할 내용이 없으므로 204가 일반적으로 쓰입니다.

POST를 멱등적으로 만들려면 어떻게 하나요?

멱등성 키를 사용하세요. 클라이언트가 각 의도된 작업마다 고유한 키를 생성해 요청과 함께 보냅니다. 서버는 어떤 키를 처리했는지 추적하며, 이미 처리된 키가 담긴 요청이 도착하면 다시 처리하는 대신 원래 응답을 반환합니다. Stripe를 비롯한 결제 API들이 이 패턴을 사용합니다.

Беше ли полезна тази страница?

😔
🤨
😃