개념
HTTP는 클라이언트와 서버 사이에 이루어지는 요청/응답 프로토콜입니다. 여기서 프로토콜은 약속
, 규약
, 협약
을 나타냅니다. 즉, 클라이언트와 서버 사이에 이루어지는 요청과 응답의 규칙을 정의한 것입니다.
이러한 약속된 내용을 통해 HTTP Method는 주어진 리소스에 수행하길 원하는 동작을 나타냅니다.
특징
안전한 메소드(Safe Methods)
- 안전한 메소드는 서버의 상태를 바꾸지 않는 것입니다.
- 읽기 작업만 수행하는 메소드는
GET
,HEAD
,OPTION
가 있습니다. - 안전한 메소드는
멱등성
을 갖지만, 멱등성을 가고 있다고 모두 안전한 메소드는 아닙니다.
멱등성(Idempotent Methods)
- 멱등성은 수학이나 전산학에서 나오는 용어로, 연산의 한 성질을 나타냅니다.
- 연산을 여러 번 적용하더라도 결과가 달라지지 않는 성질을 의미합니다.
- 동일한 요청을 한 번 보내느 것과 여러 번 연속으로 보내는 것이 같은 효과를 나타냅니다.
- 올바르게 구현하였다고 가정할 경우,
GET
,HEAD
,PUT
,DELETE
메소드는 멱등성을 가지고 있습니다.- 여기서, 왜
DELETE
는 멱등성일까요?- POST를 이용해서 데이터를 생성하였다고 가정해봅시다.
- DELETE를 이용해서 데이터를 삭제를 하였고 성공으로 Http Status 200 응답 코드를 받았습니다.
- 삭제 요청한 것을 잊어버리고 다시 삭제를 요청하였는데, Http Status 404 응답 코드를 받았습니다.
- 멱등성은 연산은 여러 번 적용하더라도 결과가 달라지지 않는 것이라고 하였는데, 200 → 404로 달라졌습니다.
- 하지만 이렇게 생각해볼 수 있습니다. 처음 DELETE 요청으로 자원이 삭제가 되었습니다. 그 다음 요청에도 자원이 삭제되었기 때문에 결과가 동일하다고 볼 수 있습니다.
- 여기서, 왜
- 모든 안전한 메소드는 멱등성을 갖고 있습니다.
Cacheable Methods
- 캐시는 HTTP 응답을 나중에 검색 및 사용할 수 있도록 저장하는 것을 이야기합니다.
- 모든 HTTP 응답을 캐시할 수 있는 것은 아닙니다.
- 캐시 가능한 메소드는 대표적으로
GET
,HEAD
입니다. - 캐시가 가능한 상태코드가 따로 정의되어 있습니다.
200, 203, 204, 206, 300, 301, 404, 405, 410, 414, 501
- 캐시를 제어할 수 있는 HTTP 헤더 코드가 있습니다.
Cache-Control
은 HTTP/1.1에서 추가된 기능으로 여러 캐싱 정책을 제공하며 자세한 내용은 아래 내용 참고하면 됩니다.- 자세한 내용은 아래 참고 바랍니다.
- Cahce-Controller
종류
Http Method의 종류에는 총 8가지가 있습니다. 자주 사용한 메소드 5가지와 그 외 메소드 4가지가 있습니다. 메소드는 다음과 같습니다.
GET, POST, PUT, DELETE, PATCH, HEAD, CONNECT, OPTIONS, TRACE
아래 URL은 참고용입니다.
RFC 7231, section 4: Request methods
각 HTTP Method들에 대해서 실제 구현한 예시를 통해서 알아보도록 하겠습니다.
모든 소스는 Github를 통해서 확인할 수 있습니다.
개발 환경
- Java : 1.8
- Spring Boot : 2.6.2
- 그 외 JPA, Lombok, h2 사용
초기 데이터를 아래와 같이 넣어두었습니다.
INSERT INTO book(id, name) values(1, '자바의정석');
INSERT INTO book(id, name) values(2, '자바 ORM 표준 JPA 표준 프로그래밍');
INSERT INTO book(id, name) values(3, '켄트 벡의 구현 팬턴');
INSERT INTO book(id, name) values(4, '클린 코드');
INSERT INTO book(id, name) values(5, '리팩토링 2탄');
그러면, 책을 관리하는 애플리케이션을 통해서 HTTP Method 정리를 해보겠습니다.
GET
책 정보를 조회하려고 합니다. 원하는 책 하나를 조회 요청할 수 도 있고 책 전체 목록을 조회 요청할 수 도 있습니다. 여기서는 책 하나를 조회 요청해보겠습니다.
정보를 조회할 때는 URL path와 query 파라미터를 사용합니다. 두 개를 같이 사용할 수도, 따로 사용할 수도 있습니다.
URL Path
- 리소스의 경로를 나타내며, 계층적 구조를 표현합니다.
다음을 호출해보겠습니다.
GET http://localhost:8080/book/1
결과는 다음과 같습니다.
HTTP/1.1 200
Content-Type: application/json
Transfer-Encoding: chunked
Date: Fri, 14 Jan 2022 14:35:01 GMT
Keep-Alive: timeout=60
Connection: keep-alive
{
"id": 1,
"name": "자바의정석"
}
Response code: 200; Time: 298ms; Content length: 23 bytes
GET은 안전한 메소드입니다. 그렇다면 멱등성일까요? 몇 번은 요청해도 응답값은 동일하기 때문에 멱등성을 갖고 있습니다.
URL Query 파라미터
- key=value 형태를 나타내며, ?로 시작, &로 추가 가능합니다.
- ex) ?keyA=value&keyB=valueB
- query parameter, query string 등으로 불리며, 문자 형태로 전송됩니다.
다음을 호출해보겠습니다.
GET http://localhost:8080/book?id=1&name=자바의정석
결과는 위와 동일합니다.
HTTP/1.1 200
Content-Type: application/json
Transfer-Encoding: chunked
Date: Fri, 14 Jan 2022 14:51:58 GMT
Keep-Alive: timeout=60
Connection: keep-alive
{
"id": 1,
"name": "자바의정석"
}
Response code: 200; Time: 228ms; Content length: 23 bytes
정리
- GET은 읽기 작업을 수행하기 때문에 안전한 메소드입니다.
- GET은 안전한 메소드라서 멱등성을 만족합니다. 한 번 요청을 보내는 것과 동일한 요청을 보내는 것의 대한 응답값이 동일합니다.
- GET은 요청 Body가 없습니다.
- GET은 응답 데이터가 존재합니다.
- GET은 URL 패스와 쿼리 파라미터를 자원 조회를 요청할 수 있습니다.
- URL에 길이 제한이 있으며
2,048
자까지 제한합니다. - GET은 캐시 대상입니다.
- GET은 안전한 메소드입니다.
- GET은 멱등성을 보장합니다.
- GET는 HTML Form을 허용합니다.
POST
새로운 책을 등록하려고 합니다. 그러려면 책 정보를 작성해서 작성된 정보를 넘겨줘야 합니다.
다음과 같이 작성하여 요청해보도록 하겠습니다.
POST http://localhost:8080/book
Content-Type: application/json
{
"name": "함께자라기"
}
결과는 다음과 같습니다.
HTTP/1.1 201
Location: /book/6
Content-Type: application/json
Transfer-Encoding: chunked
Date: Fri, 14 Jan 2022 15:11:05 GMT
Keep-Alive: timeout=60
Connection: keep-alive
{
"id": 6,
"name": "함께자라기"
}
Response code: 201; Time: 503ms; Content length: 23 bytes
POST는 안전한 메소드가 아닙니다. 그래서 같은 내용으로 시도하였을 경우 동일한 결과가 나타나면 안됩니다. 같은 내용으로 다시 시도해보면 다음과 같은 2가지 결과를 얻을 수 있습니다.
첫번째
- 이름이 중복되어도 등록은 가능하며 id가 변경됩니다.
HTTP/1.1 201
Location: /book/6
Content-Type: application/json
Transfer-Encoding: chunked
Date: Fri, 14 Jan 2022 15:11:05 GMT
Keep-Alive: timeout=60
Connection: keep-alive
{
"id": 7,
"name": "함께자라기"
}
Response code: 201; Time: 503ms; Content length: 23 bytes
두번째
- 이름이 중복된 경우 등록 불가 처리를 하였습니다.
HTTP/1.1 500
Content-Type: application/json
Transfer-Encoding: chunked
Date: Fri, 14 Jan 2022 15:20:59 GMT
Connection: close
{
"timestamp": "2022-01-14T15:20:59.262+00:00",
"status": 500,
"error": "Internal Server Error",
"message": "이미 등록된 책입니다.",
"path": "/book"
}
Response code: 500; Time: 155ms; Content length: 130 bytes
정리
- POST는 새로운 자원 등록을 요청할 수 있습니다.
- PUT은 요청 Body가 존재합니다.
- PUT은 응답 Body가 존재합니다.
- POST는 안전한 메소드는 아닙니다.
- POST는 안전한 메소드가 아니기 때문에 멱등이 아닙니다.
- POST는 응답 데이터기 존재합니다.
- POST는 캐시가 가능하지만 사용하기는 어렵습니다.
- POST는 GET과는 다르게 요청 Body의 데이터를 보낼 수 있습니다.
- 요청 Body의 데이터를 보낼 수 있기 때문에 전송양에 길이 제한이 없으며 대용량 데이터를 보낼 수 있습니다.
- POST는 HTML Form을 허용합니다.
PUT
등록된 책의 정보를 수정하려고 합니다. 여기서 책의 가격 정보를 나타내는 필드를 추가하여서 진행해보겠습니다.
다음과 같이 작성하여 요청하겠습니다.
PUT http://localhost:8080/book/6
Content-Type: application/json
{
"name" : "스프링 부트와 AWS로 혼자 구현하는 웹 서비스",
"price": 18000
}
응답 결과는 다음과 같습니다. PUT은 조회 대상 자원이 있고 요청한 정보가 성공적으로 수정이 된다면 200
(OK) 또는 204
(No Content) 응답을 보내 성공을 알려줘야 합니다. 여기서는 새로 생성되었기 때문에 200
을 사용하였습니다.
HTTP/1.1 200
Content-Length: 0
Date: Fri, 14 Jan 2022 16:11:19 GMT
Keep-Alive: timeout=60
Connection: keep-alive
<Response body is empty>
Response code: 200; Time: 203ms; Content length: 0 bytes
PUT은 안전한 메소드는 아니지만 멱등성을 가지고 있습니다. 한 번을 보내도, 여러 번을 연속으로 보내도 응답 결과는 같습니다.
7번의 책 정보를 등록을 하려고 합니다. 다음과 같이 작성하여 요청하겠습니다. 7번은 현재 등록된 정보가 없습니다.
PUT http://localhost:8080/book/7
Content-Type: application/json
{
"name" : "스프링 부트와 AWS로 혼자 구현하는 웹 서비스",
"price": 18000
}
응답은 다음과 같습니다.
HTTP/1.1 201
Location: /book/6
Content-Length: 0
Date: Fri, 14 Jan 2022 17:02:10 GMT
Keep-Alive: timeout=60
Connection: keep-alive
<Response body is empty>
Response code: 201; Time: 391ms; Content length: 0 bytes
PUT은 대상 자원이 존재하지 않고 요청한 정보가 성공적으로 생성을 한 경우, 201
(Created) 응답을 보내야 합니다.
정리
- PUT은 요청 Body가 존재합니다.
- PUT은 응답 Body가 존재할수도 있고 존재하지 않을수도 있습니다.
- PUT은 요청한 대상 자원이 존재한다면 정보를 수정할 수 있습니다.
- PUT은 요청한 대상 정보가 완전히 대체됩니다.
- 파일이 존재할때 덮어쓰는것과 파일이 존재하지 않을 때 새롭게 생성하는 것과 비슷한 원리입니다.
- PUT은 요청한 대상 자원이 존재하지 않는다면 새로운 정보를 생성할 수 있습니다.
- PUT은 안전한 메소드가 아닙니다.
- PUT은 멱등성을 보장받습니다.
- 요청 Body의 데이터를 보낼 수 있기 때문에 전송양에 길이 제한이 없으며 대용량 데이터를 보낼 수 있습니다.
- PUT은 캐시 대상이 아닙니다.
- PUT은 클라이언트가 리소스 위치를 알고 URI를 지정합니다.
- PUT은 HTML Form을 허용하지 않습니다.
PATCH
등록된 책의 가격이 변동되어서 가격만 수정하려고 합니다. 다음과 같이 작성하여 요청하겠습니다.
PATCH http://localhost:8080/book/6
Content-Type: application/json
{
"price" : "40000"
}
응답은 다음과 같습니다.
HTTP/1.1 200
Content-Type: application/json
Transfer-Encoding: chunked
Date: Fri, 14 Jan 2022 17:24:17 GMT
Keep-Alive: timeout=60
Connection: keep-alive
{
"id": 5,
"name": "리팩토링 2탄",
"price": 40000
}
Response code: 200; Time: 185ms; Content length: 39 bytes
PATCH의 응답 상태는 2xx
상태 코드를 통해서 확인할 수 있습니다.
PATCH은 API를 구현하는 방식의 따라서 PUT처럼 멱등성을 보장받을 수 있고 보장받지 않을 수도 있습니다.
실제 현업에서 어떤 부분까지 사용하는지 궁금합니다. 댓글로 알려주신다면 감사하겠습니다.
정리
- PATCH는 요청 Body가 존재합니다.
- PATCH는 응답 Body가 존재합니다.
- PATCH는 안전하지 않은 메소드입니다.
- PATCH는 멱등성이 아닙니다.
- 구현 방식의 따라서 멱등성을 보장받을 수 있습니다.
- PATCH는 캐시 대상이 아닙니다.
- PATCH는 HTML Form을 허용하지 않습니다.
DELETE
등록된 책 중 저자의 요청으로 인하여 삭제(?)를 해보도록 하겠습니다. 다음과 같이 작성하여 요청하겠습니다.
DELETE http://localhost:8080/book/5
응답은 다음과 같습니다.
HTTP/1.1 204
Date: Fri, 14 Jan 2022 17:42:25 GMT
Keep-Alive: timeout=60
Connection: keep-alive
<Response body is empty>
Response code: 204; Time: 304ms; Content length: 0 bytes
DELETE은 요청한 자원을 삭제하고 No Content
를 응답으로 전달합니다.
정리
- DELETE는 요청 Body가 존재할 수 있습니다.
- DELETE는 응답 Body가 존재할 수 있습니다.
- DELETE는 안전하지 않은 메소드입니다.
- DELETE는 멱등성을 보장합니다.
- DELETE는 캐시 가능하지 않습니다.
- DELETE는 HTML Form을 허용하지 않습니다.
CONNECT
요청한 자원에 대해 양방향 연결을 시작하는 메소드입니다.
정리
- CONNECT는 요청 Body가 존재하지 않습니다.
- CONNECT는 응답 Body가 존재합니다.
- CONNECT는 안전하지 않은 메소드입니다.
- CONNECT는 멱등성을 보장하지 않습니다.
- CONNECT는 캐시 가능하지 않습니다.
- CONNECT는 홉바이홉(hop by hop)입니다.
- 데이터 통신망에서 각 패킷이 노드(또는 라우터)를 통해 전송되는 것을 비유적으로 표현한 것입니다.
- CONNECT는 HTML Form을 허용하지 않습니다.
HEAD
특정 HTTP Method에 대해서 응답받을 헤더를 요청합니다.
다음과 같이 요청할 수 있습니다.
HEAD http://localhost:8080/book/1
응답은 다음과 같습니다.
HTTP/1.1 200
Content-Type: application/json
Transfer-Encoding: chunked
Date: Fri, 14 Jan 2022 17:51:54 GMT
Keep-Alive: timeout=60
Connection: keep-alive
<Response body is empty>
Response code: 200; Time: 176ms; Content length: 0 bytes
응답 Body는 비어 있으며 응답 Header 정보가 담고 있습니다.
정리
- HEAD는 요청 Body가 존재하지 않습니다.
- HEAD는 응답 Body가 존재하지 않습니다.
- HEAD는 안전한 메소드입니다.
- HEAD는 멱등성을 보장합니다.
- HEAD는 캐시 가능합니다.
- HEAD는 HTML Form을 허용하지 않습니다.
OPTIONS
- 자원의 대한 통신 옵션 정보를 확인하기 위해 사용됩니다.
다음과 같이 요청할 수 있습니다.
OPTIONS http://localhost:8080/book/1
응답은 다음과 같습니다.
HTTP/1.1 200
Allow: DELETE,GET,HEAD,PUT,PATCH,OPTIONS
Accept-Patch:
Content-Length: 0
Date: Fri, 14 Jan 2022 17:54:12 GMT
Keep-Alive: timeout=60
Connection: keep-alive
<Response body is empty>
Response code: 200; Time: 191ms; Content length: 0 bytes
Allow 헤더를 통해서 허용되는 Method를 확인할 수 있습니다.
정리
- OPTIONS는 요청 Body가 존재하지 않습니다.
- OPTIONS는 응답 Body가 존재합니다.
- OPTIONS는 안전한 메소드입니다.
- OPTIONS는 멱등성을 보장합니다.
- OPTIONS는 캐시 가능하지 않습니다.
- OPTIONS는 HTML Form을 허용하지 않습니다.
TRACE
- 목적 리소스의 경로를 따라 메시지 loop-back 테스트를 합니다.
정리
- TRACE 요청 Body가 존재하지 않습니다.
- TRACE 응답 Body가 존재하지 않습니다.
- TRACE 안전한 메소드입니다.
- TRACE 멱등성을 보장합니다.
- TRACE 캐시 가능하지 않습니다.
- TRACE는 HTML Form을 허용하지 않습니다.
마무리
- HTTP는 클라이언트와 서버 간의 약속된 규칙을 말합니다.
- HTTP Methods는 3가지 특성을 갖고 있습니다.
- 안전한 메소드
- 멱등성
- 캐시 가능
- HTTP Methods의 종류는 9개이며 자주 사용하는 5개(GET, POST, PUT, PATCH, DELETE)와 자주 사용하지 않는 4개(HEAD, OPTIONS, CONNECT, TRACE)로 나눌 수 있습니다.
- 다음과 같이 표로 정리해보겠습니다.
안전한 메소드 | 멱등성 | 캐시 가능 | 요청 Body | 응답 Body | |
---|---|---|---|---|---|
GET | O | O | O | X | O |
POST | X | X | X | O | O |
PUT | X | O | X | O | X |
PATCH | X | X | X | O | O |
DELETE | X | O | X | O | X |
HEAD | O | O | O | X | X |
OPTIONS | O | O | X | X | O |
CONNECT | X | X | X | X | O |
TRACE |
댓글