HTTP 메서드
HTTP Method
도구
요청이 무엇을 하려는 것인지 받는 쪽에 알려 주는 동사로, 같은 주소라도 이 값에 따라 읽기와 생성과 삭제가 갈립니다.
등장 배경
웹이 문서를 보여 주기만 하던 시절에는 요청의 종류를 나눌 이유가 없었습니다. 주소를 주면 그 문서가 돌아오는 것이 전부였습니다. 화면에서 값을 입력해 서버로 보내기 시작하면서 사정이 달라졌습니다. 초기에는 주소 안에 동작 이름을 넣어 구분했습니다. /getPost 로 읽고 /deletePost 로 지우는 식입니다. 규칙은 팀마다 달라서 /removePost 를 쓰는 곳도 /post_delete 를 쓰는 곳도 있었고, 남의 창구에 붙으려면 문서를 끝까지 읽는 수밖에 없었습니다.
문제는 그 안쪽에 하나 더 있었습니다. 요청이 오가는 길에는 응답을 잠시 저장해 두는 장치가 끼어 있는데, 요청 본문을 뜯어보지는 않습니다. 주소에 숨은 동작 이름을 알아볼 수 없으니 무엇을 저장해도 되는지 판단할 근거가 없었습니다. 읽기 요청은 다시 보내도 그만이지만 결제 요청은 두 번 청구됩니다. 그런데 둘이 밖에서는 똑같이 생겼습니다.
HTTP 메서드는 그 판단 근거를 요청의 맨 앞으로 끌어낸 장치입니다. 주소와 별개로 동사를 붙이게 해서, 본문을 열지 않아도 무슨 일이 벌어질 요청인지 누구나 알게 만들었습니다.
해결하는 문제
같은 주소를 두고도 무엇을 하려는 요청인지 본문을 열기 전에 알 수 있게 하는 문제를 풉니다. /documents/34 라는 주소 하나에 어떤 동사가 붙느냐로 읽기와 수정과 삭제가 갈립니다.
실제로 쓰는 동사는 다섯 개입니다.
- GET — 가져옵니다. 문서 34번의 내용을 달라는 요청이고 서버 쪽에 아무것도 남기지 않습니다.
- POST — 새로 만듭니다. 제목과 내용을 함께 보내면 만들어진 문서의 번호를 서버가 정해 돌려줍니다.
- PUT — 통째로 바꿉니다. 34번을 지금 보내는 내용으로 덮어쓰고, 보내지 않은 칸은 비워집니다.
- PATCH — 일부만 바꿉니다. 34번의 제목만 고치고 나머지는 그대로 둡니다.
- DELETE — 지웁니다. 34번을 없애 달라는 요청입니다.
이 다섯을 이름표로만 보면 절반만 본 것입니다. 동사마다 지키기로 한 성질이 붙어 있고 길 위의 장치들이 그것을 믿고 움직입니다. 성질은 둘입니다.
첫째는 서버 쪽을 바꾸느냐입니다. GET 은 바꾸지 않기로 약속된 동사여서, 한 번 받은 응답을 저장해 두었다가 다음에 그대로 내주는 캐싱이 GET 에만 걸립니다.
둘째는 같은 요청을 여러 번 보내도 결과가 같으냐, 즉 멱등성입니다. 34번을 지우는 요청을 세 번 보내도 없어진 상태 하나로 끝나므로 DELETE 는 멱등합니다. POST 는 세 번 보내면 문서가 세 개 생깁니다. 통신이 끊겨 응답을 못 받았을 때 그냥 다시 쏴도 되는지가 여기서 갈립니다.
대안
메서드 없이 창구를 만드는 길도 쓰입니다. 대신 길 위의 장치들이 해 주던 판단을 직접 떠안습니다.
첫째는 주소에 동작 이름을 넣는 방식입니다. 옛 방식이지만 사내 서비스끼리 주고받는 자리, 특히 동작이 읽기·쓰기·지우기에 딱 떨어지지 않을 때는 지금도 쓸 만합니다. 문서를 다른 팀에 넘기는 동작이라면 /transferOwnership 이라고 적으면 끝납니다. 대신 창구 수가 기능 수만큼 늘고 중간 장치는 끝까지 아무것도 모릅니다.
둘째는 모든 요청을 한 가지로 통일하는 방식입니다. 필요한 항목만 골라 받는 GraphQL이 여기 가깝습니다. 읽든 쓰든 전부 POST 로 보내고 무엇을 할지는 본문의 질의문이 정합니다. 화면 하나에 필요한 값을 한 번에 받는 이점이 크지만, 밖에서 보면 모든 요청이 똑같이 생겨 HTTP 층의 캐싱을 쓰지 못합니다.
셋째는 절충입니다. GET 과 POST 둘만 쓰고 나머지는 POST 안에서 처리하는 방식이고, 웹 프레임워크들은 실제 동사를 숨은 값으로 실어 보내는 우회로를 갖고 있습니다.
셋 다 도는 방식이지만 밖에 열어 남이 붙게 할 창구라면 다릅니다. 처음 보는 사람이 주소와 동사만으로 무슨 일이 일어날지 짐작할 수 있어야 하고, 자원을 주소로 다루는 REST 가 널리 쓰이는 이유가 여기 있습니다.
실무 용례
"이거 GET 으로 열지 마세요. 부르기만 해도 상태가 바뀌잖아요."
읽기 전용이어야 할 동사에 바꾸는 동작을 넣어 두면 링크를 훑는 도구가 사고를 낸다는 경고입니다.
"응답이 안 와서 재시도해도 되나요? PUT 이면 그냥 다시 쏘세요."
멱등한 동사라 같은 요청이 두 번 도착해도 결과가 달라지지 않는다는 뜻입니다.
"목록 조회를 왜 POST 로 만들었어요?"
검색 조건이 주소에 담기엔 너무 길어 본문으로 보낸 경우가 많고, 알고 어긴 것이면 그대로 두기도 합니다.
페이지덱 초기에 문서 목록의 삭제 버튼이 평범한 링크였습니다. 삭제 주소로 이동하는 GET 요청이었고 여섯 달 동안 아무 문제가 없었습니다. 사고는 사내에서 쓰던 브라우저 도구가 화면 안의 링크를 미리 열어 두는 기능을 켜면서 났습니다. 아무도 누르지 않았는데 문서 서른 건이 사라졌습니다. 태오가 삭제를 DELETE 로 옮기면서 정리됐고, 이후로 페이지덱은 새 창구를 만들 때 동사부터 정하고 주소를 짓습니다. 동사가 정해지면 상태 코드로 무엇을 돌려줄지도 대체로 따라오기 때문입니다.
흔한 오해
메서드의 차이를 기술적 차이로만 아는 경우가 많습니다. GET 은 주소에 값을 붙이고 POST 는 본문에 싣는다는 설명을 먼저 배우기 때문입니다. 맞는 설명이지만 중요한 쪽이 빠져 있습니다. 실제 차이는 약속입니다. 이 동사가 서버를 바꾸느냐를 모두가 믿고 움직인다는 합의가 본체이고, 본문을 싣느냐는 거기서 따라 나온 결과입니다. 순서를 뒤집어 이해하면 조회를 POST 로 만들어 놓고도 무엇이 문제인지 모릅니다. 뒤로 가기가 매번 재전송 경고를 띄우고, 주소만 복사해 보내는 일이 안 되고, 캐싱이 걸리지 않아 같은 목록을 부를 때마다 서버가 다시 계산합니다.
동사를 제대로 골랐으니 안전하다는 오해도 있습니다. DELETE 로 만들면 아무나 못 지우는 것처럼 느껴지지만, 메서드는 의도를 밝히는 표시일 뿐 권한을 막지 않습니다. 같은 주소와 동사를 흉내 낸 요청은 누구나 보냅니다. 무엇을 할 수 있는지 확인하는 인가를 서버 안에서 따로 하지 않으면, 남의 문서 번호를 넣은 DELETE 요청 하나로 남의 자료가 지워집니다.
같이 보면 좋은 페이지
마지막 업데이트 2026-09-16