HTTP 메서드 해부하기(1) - GET vs POST
사전 지식
HTTP(Hyper Text Transfer Protocol)는 요청과 응답을 통해서 데이터를 서로 주고받기 위한 통신 규약(protocol)입니다.
이때 HTTP 통신을 통해서 추가되거나, 갱신되는 대상을 웹 리소스, 자원이라고 부릅니다.
자원은 URI(Uniform Resource Identifier)에 의해서 식별됩니다. URI라고 하면 조금 생소할 수 있지만 흔히 알고 계시는 웹 페이지의 주소(URL)도 해당 위치에 존재하는 자원을 찾아가기 위한 URI입니다.
GET /90 HTTP/1.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9 ...
Accept-Encoding: gzip, deflate, br
Accept-Language: ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7
Cache-Control: max-age=0
Connection: keep-alive
Host: co1nam.tistory.com
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Sec-Fetch-User: ?1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...
위 메시지는 "co1nam.tistory.com/90"에 존재하는 자원을 내놓으라는 요청입니다. 사용자가 주소창에 "co1nam.tistory.com/90"를 입력하고 엔터를 누르는 순간, 브라우저는 해당 주소의 서버로 위와 같은 HTTP 메시지를 전송합니다. 그리고 서버에서 보내온 응답을 화면에 보여줍니다.
첫 줄에 있는 /90
은 해당 사이트에서 자원이 위치하는 경로(Path)를, HTTP/1.1
은 HTTP/1.1 프로토콜을 이용하겠다는 것을 의미합니다. 그리고 자원을 대령하라
라는 요청을 GET
으로 표현하고 있습니다. 이처럼 HTTP 메서드는 클라이언트가 특정 자원에 대한 행위를 요청하는 데 사용됩니다.
GET과 POST만 가지고도 웬만한 웹 페이지는 다 만들 수 있기 때문에 상대적으로 나머지 메서드들의 중요성은 낮다고 할 수 있습니다. 하지만 특히 REST API에서는 다른 메서드들도 활용할 필요가 있기 때문에 이렇게 HTTP 메서드의 특징과 차이점에 대해서 알아둘 필요가 있습니다.
REST API에서는 자원에 대한 행위를 HTTP 메서드를 통해서 표현해야 합니다. 즉 co1nam.tistory.com/90에 있는 내용을 수정할 수 있는 기능을 개발하려고 할 때
co1nam.tistory.com/90/modify로 요청을 보내도록 하면 안 되고
co1nam.tistory.com/90에 PUT
요청을 보내도록 해야 합니다.
서버에서는 같은 URL에 어떤 메서드로 요청을 보내는 지를 확인해서 GET
이라면 데이터를 보내주고 PUT
이라면 받아온 데이터가 기존의 내용을 대체하게끔 처리해야 합니다.
지금부터 각 메서드의 구체적인 내용을 살펴보도록 하겠습니다.
GET
: 요청 URI에 의해 식별되는 모든 정보를 가지고 온다
GET은 특정 자원을 조회하기 위한 메서드입니다. 서버에서 가져온 데이터를 화면에 뿌려주기 위해서 많이 사용되죠. 데이터를 가져오기 위한 용도이기 때문에 GET 요청에는 body(본문)가 존재하지 않습니다.
물론 HTTP 사양에 의해 금지된 것은 아니라서 원한다면 GET 요청의 본문에 데이터를 담을 수 있습니다. 하지만 그렇게 하지 않는 것을 권장합니다. 본문의 시맨틱(Semantic, 의미)이 정의되지 않았기 때문에 그런 짓을 하더라도 의미가 없기 때문입니다.
만약 서버에서 GET 요청의 본문에 담긴 데이터를 파싱 하여 처리하고, 그것이 응답에 영향을 미치게 된다면
"요청 메서드가 엔티티 바디에 대해 정의된 시맨틱을 가지고 있지 않다면 메시지 바디는 무시되어야 한다"
라는 RFC 2616을 위반하게 됩니다(자세한 내용은 클릭 클릭).
하지만 GET 요청 시에도 정보 전달이 필요한 경우가 있습니다. 예를 들어, 회원 목록을 가져오는 경우 회원 등급에 따라 필터링된 결과가 필요할 수도 있고 특정 회원 이름으로 검색한 결과가 필요할 수도 있습니다. 이때, 회원 등급이나 검색 키워드 등을 서버에 전달하기 위해서 쿼리스트링을 사용합니다.
쿼리스트링은 웹 페이지의 주소에서 물음표? 아래에 나타나는 키와 값의 쌍을 말합니다. 각각의 쌍은 & 로 연결됩니다.
google.com/search?q=apple&lang=ko&a=b&c=d |
이 주소를 주소창에 넣으면 구글 검색결과가 나타나는 것을 확인할 수 있습니다. lang 이하의 부분은 임의로 넣은 것이기 때문에 아무 의미가 없죠. GET 방식으로 전송된 데이터는 이와 같이 주소를 통해 모두 노출되기 때문에 중요한 데이터를 GET으로 전달하는 것은 피해야 합니다.
POST
: 요청에 동봉된 엔티티를 요청 URI에 의해 식별되는 자원의 새로운 하위 요소로 등록한다
GET이 자원을 가져오기 위한 메서드라면 POST는 새로운 자원을 생성하기 위한 메서드입니다. GET과는 달리 생성할 자원에 들어갈 내용을 본문에 첨부할 수 있습니다. POST는 사용자로부터 입력을 받아 자원을 생성하는 등 서버에서의 변경을 일으키기 위한 대부분의 경우에 사용되는데, 이를테면 게시판에 글을 올린다거나 회원가입을 한다거나 할 때 POST를 사용합니다.
요청 본문의 데이터 타입은 HTTP 헤더의 Content-Type에 의해 명시되며 폼 태그의 enctype 속성으로 넣어줄 수 있습니다.
<form enctype="text/plain" method="post">
<input ...>
</form>
application/x-www-form-urlencoded
GET 요청의 쿼리스트링과 같이 키=값&키=값 형태입니다.
q=query&k=key&content=foo
application/json
[
{
"name": "홍길동",
"age": 10,
"job": "백수"
},
{
"name": "고길동",
"age": 20,
"job": "가장"
}
]
흔히 알고 있는 json 타입입니다.
multipart/form-data
파일을 전송할 경우에 사용됩니다.
text/plain
일반적인 텍스트를 의미합니다.
서버에서는 POST 요청이 들어왔을 때 명시된 Content-type에 따라서 요청 본문에 있는 데이터를 어떻게 처리할 것인지 결정하게 됩니다.
PUT은 여러 번 반복해도 동일한 효과를 가지는 반면, POST의 경우 요청을 한 번 할 때마다 새로운 자원이 생성됩니다. 즉 PUT은 멱등성 idempotent을 가지지만 POST는 non-idempotent 한 메서드입니다. GET 역시 여러 번 요청을 한다고 달라지는 것이 없기 때문에 idempotent 합니다.
GET과 POST의 차이
똑같은 기능을 GET으로도 POST로도 처리할 수 있겠지만 무엇을 써야 할지 고민해야 하는 경우는 거의 없는 것 같습니다. 위에서 살펴본 것처럼 GET과 POST는 기본적으로 용도와 역할이 다르기 때문에 그 용도에 적합하게 사용하면 됩니다.
GET는 그 단어의 의미 그대로 자원을 가져오기 위해 사용하고 POST는 서버에서 자원을 생성하기 위해 사용합니다.
GET은 쿼리스트링을 통해 리소스를 전달하지만 POST는 요청 body에 리소스를 담습니다.
따라서 GET 요청 시 전달할 수 있는 리소스의 길이는 각 브라우저 정책에 따라 제한될 수 있습니다.
GET은 idempotent 하나 POST는 idempotent 하지 않습니다.
GET 요청이 성공할 경우 200(OK) 응답코드를 받지만 POST의 경우 201(CREATED)을 받아야 성공입니다.
GET 요청은 캐시될 수 있습니다. 똑같은 요청이 반복될 경우 매번 요청을 처리하지 않고 이미 캐시된 내용을 보여줌으로써 성능 향상을 가져올 수 있습니다. 개발을 하다보면, 특히 CSS를 수정하는 경우에 캐시 때문에 변경사항이 제대로 반영되지 않을 때가 많습니다. 참고로 이럴 땐 Ctrl + Shift + R 을 눌러주면 캐시를 날리고 새로고침을 해줄 수 있습니다.
또 GET 요청은 북마크할 수 있고, 브라우저 히스토리에도 남게 됩니다.
반면 POST에서는 이런 것들이 불가능합니다. POST 요청을 북마크 해서 즐겨찾기를 클릭하면 저절로 글이 작성되도록 하거나 회원가입한 이력이 기록에 남게 한다거나 할 수는 없겠죠.
참조
https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods