카카오 OAuth 로그인을 구현해 보면서, RestTemplate을 사용하게 되었는데 RestTemplate이 무엇인지와 동작원리 등에 대해 정리해보려고 합니다.
RestTemplate
- HTTP 통신을 위한 도구로 Rest API 웹 서비스와의 상호작용을 쉽게 할 수 있도록 도와주는 도구
- HTTP 메서드를 제공하고 원격 서버와 동기적, 블로킹 방식으로 Json, xml 방식으로 다양한 데이터 형식으로 통신합니다.
- Spring Framework의 핵심이 제공하는 동기식 RestClient
간단하게 외부 도메인과 Rest API을 제공하는 서비스와의 상호작용을 쉽게 해주는 도구로 해석하면 될 것 같은데요. 이제 동작 원리에 대해 설명드리도록 하겠습니다.
RestTemplate Flow
- Application이 RestTemplate을 생성하고, Uri, http method 등의 header를 담아 요청합니다.
- RestTemplate은 HttpMessageConverter를 사용하여 RequestEntity를 요청 메시지를 변환합니다.
- RestTemplate은 ClientHttpRequestFactory로부터 ClientHttpRequest를 가져와 요청을 보냅니다.
- ClientHttpRequest는 요청 메시지를 만들어 HTTP를 통해 서버와 통신합니다.
- RestTemplate은 ResponseErrorHandler로 오류를 확인하고 있다면 Error Handling 과정을 거칩니다.
- ClientHttpResponse에서 Error가 있다면, 이에 대해 처리하는 과정을 거칩니다.
- RestTemplate은 HttpMessageConverter를 이용하여 응답 메시지를 Java Object로 변환합니다.
- 애플리케이션에 반환합니다.
대략적으로 흐름이 이해되셨으면, Rest Resource와의 상호작용을 위한 메서드에 대해 알아보도록 하겠습니다.
HTTP의 요청과 응답에 대한 메서드라고 생각하시면 될 것 같습니다. 그중에서도 exchange(), execute() 메서드는 ANY 옵션으로 어떤 HTTP 메서드가 들어와도 상관이 없습니다.
exchange() vs execute()
execute()
- RestTemplate 메서드 중 가장 범용적으로 사용되며, 아래와 같은 시나리오에 적합합니다.
- 모든 URL, HTTP 메서드 조합을 사용할 경우에 사용합니다.
- 요청을 보내기 전에, RequestCallback을 통해 요청을 다양하게 수정할 경우에 사용합니다.
- 응답 데이터를 ResponseExtractor를 통해 사용자 지정 방식으로 처리할 경우에 사용합니다.
exchange()
- execute에 비해 편리하게 사용할 수 있습니다.
- RequestCallback 대신, HttpEntity를 통해 body, header 등을 바로 전달할 수 있습니다.
- ResponseExtractor 없이, 내부적으로 응답 데이터를 처리합니다.
HTTP 요청, 응답의 자동 변환 및 역직렬화 (첨부한 다이어그램 참고)
- 요청 및 응답을 자동으로 변환하고 역직렬화하는 기능을 제공합니다.
- 변환은 내부적으로 MessageConverter에 의해 자동으로 처리됩니다.
- MessageConverter는 요청 및 응답 Body의 데이터 형식을 반환합니다.
HTTP 요청, 응답을 다양한 형식으로 처리
- Accept: 클라이언트가 서버에서 받기 원하는 미디어 타입을 지정합니다.
- Content-Type: 서버에서 클라이언트로 보내는 미디어 타입을 지정합니다.
- text/pain, application/json, application/xml 방식이 있습니다.
Header, Query Parameter 설정 지원
- HttpHeaders 클래스의 add 메서드를 활용하여 Request Header를 설정합니다.
- UriComponentsBuilder 클래스의 queryParam 메서드를 활용하여 Query Parameter를 설정합니다.
HTTP 요청/응답에 대한 로깅 지원
- HTTP 요청과 응답을 가로채서 로그를 찍어볼 수 있습니다.
- RestTemplate Bean 주입시, 구현한 Interceptor를 함께 주입시켜야 합니다.
사용 예시
RestTemplate restTemplate = new RestTemplateBuilder()
.interceptors(new RestTemplateHeaderModifierInterceptor())
.build();
public class RestTemplateHeaderModifierInterceptor
implements ClientHttpRequestInterceptor {
@Override
public ClientHttpResponse intercept(
HttpRequest request,
byte[] body,
ClientHttpRequestExecution execution) throws IOException {
ClientHttpResponse response = execution.execute(request, body);
response.getHeaders().add("Foo", "bar");
return response;
}
}
@Configuration
public class RestClientConfig {
@Bean
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate();
List<ClientHttpRequestInterceptor> interceptors
= restTemplate.getInterceptors();
if (CollectionUtils.isEmpty(interceptors)) {
interceptors = new ArrayList<>();
}
interceptors.add(new RestTemplateHeaderModifierInterceptor());
restTemplate.setInterceptors(interceptors);
return restTemplate;
}
}
<참고 자료>
https://sjh836.tistory.com/141
https://stackoverflow.com/questions/52364187/resttemplate-exchange-vs-postforentity-vs-execute
'Java > Spring' 카테고리의 다른 글
[Spring] Spring Cloud Gateway (+ Eureka Server) (2) | 2024.10.26 |
---|---|
[Spring] Spring Webflux (1) | 2024.10.23 |
[Spring] org.springframework.orm.jpa.JpaSystemException: Error attempting to apply AttributeConverter (3) | 2024.09.26 |
[Spring] @Transactional isolation level, propagation level, timeout (5) | 2024.09.23 |
[Spring] Spring Security 동작 원리 파악 (id, pw 기반의 basic auth 방식) (0) | 2024.09.06 |