보통 자원을 조회하거나 검색할 때는 GET 방식을,
자원을 생성(등록)하는 경우 POST 방식을 사용한다.
하지만 언제나 그런 것은 아니다.
그렇기 때문에 상황과 기능에 맞는 메서드를 지정하기
위해서 이번에는 GET과 POST 메서드의 상세한 특징에
대해 주요 키워드와 함께 살펴보고자 한다.
'안전한' 메서드와 '멱등성'
GET 메서드를 사용할 경우에는
해당 요청이 '안전한 요청'이어야 한다.
여기서 '안전하다'는 의미는 해당 요청이
서버의 자원 상태를 변경하지 않는 것을 말한다.
* HTTP/1.1 명세 문서를 참고하면,
GET, HEAD, OPTIONS가 각각
안전한 메서드라고 나와 있다.
GET 메서드 API를 '안전한 메서드'로 만드는
것도 매우 중요하다. 왜냐하면 GET 메서드는
특히 웹 브라우저에서 특정 URL에 접속하기만 해도
요청이 날아갈 수 있기 때문이다.
실수로도 얼마든지 요청이 날아갈 수 있으므로
자원의 상태를 변경하는 API에 GET 메서드를
사용하는 것은 위험한 API 설계이다.
GET은 대표적으로 멱등성이 있는 메서드이고,
POST는 멱등성이 없는 메서드에 해당한다.
* 멱등성이란?
한 번 호출한 것과 여러 번 호출한 것이 같은 자원의
상태를 가지는 것을 의미한다.
POST로 생성 요청을 보내면,
한 번 보냈을 때와 비교해서 두 번, 세 번, 계속 보내도
보낼 때마다 자원이 계속해서 하나씩 늘어나므로
POST는 대표적인 멱등성이 없는 메서드이다.
반면 멱등성이 있는 메서드로는 GET, PUT, DELETE가 있다.
GET은 안전한 메서드이면서 동시에 멱등성이 있는
메서드에 해당한다. 주로 데이터를 조회하거나 HTML 문서를
요청하는 경우 GET 메서드를 사용하기 때문에 호출해도
자원의 상태가 바뀌지 않는다.
PUT과 DELETE 역시 멱등성이 있는 메서드인데,
한 번 수정 요청을 한 경우, 이후 같은 수정 요청을 해도
해당 데이터는 계속 자원 상태를 유지하기 때문이다.
한 번 삭제 요청을 한 경우에도 이후 같은 삭제 요청을
반복해도 자원의 상태는 삭제 상태로, 이전과 달라지지 않는다.
예를 들어 3번 게시글을 삭제해달라고 요청하면,
이후 계속해서 3번 게시글을 삭제해달라고 해도
이미 삭제된 상태에서 없는 3번 게시글을 삭제해달라고
하는 요청은 결국 자원의 상태에 아무런 영향을 주지 않는다.
변경 역시 2번 게시글의 제목을 '새 제목'으로변경해달라고
요청한 뒤에 같은 내용으로 제목을'새 제목'으로 변경해달라고
요청해도 제목은이전과 같은 상태로 '새 제목'이라고 나와 있기
때문에 자원 상태에 변화가 없다고 본 것이다.
GET 메서드 사용 시 주의할 점
GET 메서드는 HTTP 요청에서
주로 쿼리 매개변수를 사용하여 데이터를 전송한다.
즉, URL의 일부로 데이터를 전송하는 방식을 말한다.
(쿼리 파라미터 혹은 쿼리 스트링이라고 한다.
(참고로 이때 쿼리문자열에 포함되어 전송되기
때문에 길이의 제한이 있다. 2^8미만으로
최대 255자까지 저장가능하다.)
쿼리 파라미터의 키(key)와 값(value)은 '='으로 구분되고
여러 개의 쿼리 파라미터를 전달할 때는 '&'으로
묶인다. 예) https://www.google.com/search?q=123&n=456&...
이 외에도 데이터를 경로(Path)의 일부인 패스 베리어블(Path variable)로
전달하는 방법도 있다. 예) https://www.google.com/article/123
중요한 점은 GET 메서드의 경우 HTTP 요청 바디를
사용하는 것이 적절하지 않다는 점이다.
HTTP 요청의 바디에 데이터를 담아 전송하는 것은
일반적으로 GET 메서드의 사용 방식에 부합하지 않는다.
만약 데이터를 전송해야 한다면 POST나 다른 메서드를 고려해야 한다.
GET 메서드의 경우 HTTP 요청 바디를 사용하는 것이
적절하지 않은 이유는 다음과 같이 3가지로 들 수 있다.
1. 캐싱 관련
GET 요청은 캐싱될 수 있다. 캐싱은 같은 요청이 반복될 때
서버에 다시 요청하지 않고 이전에 받은 응답을 사용하여
성능을 향상시키는 것을 말한다.
GET 요청에서는 쿼리 매개변수가 URL에 포함되므로
캐시가 요청을 식별하고 저장할 수 있습니다.
반면에 요청 바디는 캐시 키로 사용되지 않기 때문에
캐싱의 이점을 제공받지 못할 수 있다.
2. 북마크 관련
GET 요청은 브라우저의 주소 표시줄에 직접 표시될 수 있다.
이는 사용자가 해당 URL을 북마크하거나 공유할 때 편리하다.
그러나 요청 바디에 데이터를 담으면 URL이 길어지고
가독성이 떨어지며, 북마크를 하기 어려울 수 있다.
3. 보안 관련
일반적으로 GET 요청에서는 데이터가 URL에 노출되므로
민감한 데이터를 전송하는 데 적합하지 않다.
URL은 브라우저 히스토리나 서버 로그와 같은 장소에
노출될 수 있으므로 보안상의 이슈가 발생할 수 있다.
따라서 GET 대신에 다른 메서드, 예를 들어 POST를 사용하여
요청 바디를 사용하면 데이터가 URL에 노출되지 않고
HTTP 요청의 일부로 전송되므로 보안적인 측면에서 더 안전하다.
HTTP 요청 바디
HTTP 요청 바디는 HTTP 요청 메시지의 일부로서,
클라이언트가 서버에게 전달하려는 데이터를 포함한다.
이 데이터는 일반적으로 HTML 폼 데이터, JSON, XML 등의
구조화된 정보에 해당한다. 요청 바디는 HTTP 메서드와
함께 사용되며, 주로 POST 및 PUT 메서드와 함께 사용된다.
요청 바디의 내용은 요청 헤더와 별도로 전송되며,
일반적으로 텍스트 또는 이진 데이터의 형태로 전송된다.
클라이언트가 서버로 데이터를 보내는 경우,
요청 바디를 사용하여 해당 데이터를 포함시키게 한다.
이는 웹 애플리케이션에서 사용자가 제출한 양식 데이터를
서버로 전송하거나, API를 통해 데이터를 전송하는 등의 경우에 사용된다.
요청 바디의 내용은 Content-Type 헤더에 의해 정의된다.
이 헤더는 요청 바디의 데이터 유형(예: 텍스트 또는 이진)과
형식(예: JSON, XML 등)을 명시한다.
따라서 요청을 처리하는 서버는 Content-Type 헤더를
확인하여 요청 바디의 데이터를 올바르게 해석한다.
HTML 요청 바디를 사용하는 경우
1. 데이터의 크기가 크거나 민감한 경우
GET 요청은 URL에 데이터를 노출시키므로, 민감한 경우,
즉 보안이 필요한 경우 요청 바디를 사용하여 데이터를
전송하는 것이 적절하다. 왜냐하면 POST방식의 HTTP 요청은
브라우저에 의해 캐시되지 않으며 브라우저 히스토리에도 남지 않기 때문이다.
만약 데이터가 크다면/길이가 길다면, POST방식으로 요청하는 것이 적합한데,
그 이유는 POST방식의 HTTP요청에 의한 데이터는 쿼리문자열과는 별도로
전송되기 때문이다. 따라서 데이터의 길이에 대한 제한이 없다.
2. 서버에 상태 변경이 필요한 경우
데이터를 서버로 전송하여 상태 변경이 필요한 경우에는
요청 바디를 사용하는 것이 일반적이다.
예를 들어, 사용자가 로그인할 때는 사용자 이름과
비밀번호를 요청 바디에 담아 POST 요청을 보낸다.
3. RESTful API에서의 자원 생성 또는 업데이트
RESTful API에서는 POST 및 PUT 메서드를 사용하여
자원을 생성하거나 업데이트한다.
이러한 경우에는 요청 바디를 사용하여 데이터를 전송한다.
아래는 Java와 Spring Framework를 사용하여
HTTP POST 요청을 보내고 요청 바디에
JSON 데이터를 포함하는 예시 코드이다.
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.web.client.RestTemplate;
public class Main {
public static void main(String[] args) {
// JSON 데이터 생성
String json = "{\"name\": \"John\", \"age\": 30, \"city\": \"New York\"}";
// HTTP 요청 헤더 설정
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
// HTTP 요청 바디에 JSON 데이터 포함
HttpEntity<String> requestEntity = new HttpEntity<>(json, headers);
// POST 요청 보낼 URL
String url = "https://example.com/api/users";
// RestTemplate을 사용하여 POST 요청 보내기
RestTemplate restTemplate = new RestTemplate();
try {
// POST 요청 보내기
restTemplate.postForObject(url, requestEntity, String.class);
System.out.println("요청이 성공적으로 완료되었습니다.");
} catch (Exception e) {
System.out.println("오류가 발생했습니다: " + e.getMessage());
}
}
}
이 코드는 Spring Framework의 RestTemplate을
사용하여 POST 요청을 보내고 있다.
요청 바디에 포함할 JSON 데이터를 문자열로 생성하고,
HttpHeaders를 사용하여 요청의 Content-Type을
JSON으로 설정한다. 그리고 HttpEntity를 사용하여
요청 바디에 JSON 데이터를 포함시킨다.
RestTemplate의 postForObject() 메서드를 사용하여
POST 요청을 보내고 응답을 처리한다.
위 코드를 실행하려면 Spring Framework의 의존성을
포함한 Maven 또는 Gradle 프로젝트를 사용하여
프로젝트를 설정해야 한다.
'Web > Basic' 카테고리의 다른 글
[Web] 웹 브라우저와 서버의 상호작용 방법 (0) | 2024.02.27 |
---|---|
[Web] 블로킹(blocking)과 논블로킹(non-blocking) + 콜백(callback) 함수 (0) | 2024.02.23 |
[Web] 동기 방식(Synchronous)과 비동기 방식 (Asynchronous) (0) | 2024.02.23 |
[Web] 웹 서버와 WAS : 아파치(Apache)와 톰캣(Tomcat) (0) | 2024.01.30 |
[Web] 웹 개발의 시작 - client와 server의 개념 (0) | 2024.01.21 |