서버 간의 통신
다른 서버가 API를 호출해서 사용할 수 있게 구성되어 웹 요청을 보내고 응답 받을 수 있게 도와주는 "WebClient"에 대해 알아보겠습니다.
WebClient
일반적으로 실제 운영환경에 적용되는 애플리케이션은 정식 버전으로 출시된 스프링 부트의 버전보다 낮은 경우가 많다.
그렇기 때문에 "RestTemplate" 을 많이 사용하고 있다.
하지만 최신 버전에서는 "RestTemplate" 이 지원 중단되어 WebClient를 사용할 것을 권고하고 있다.
Spring WebFlux
- HTTP 요청을 수행하는 클라이언트로 WebClient를 제공한다.
- WebClient는 리액터(Reactor) 기반으로 동작하는 API 입니다.
- 리액터 기반으로 스레드와 동시성 문제를 벗어나 비동기 형식으로 사용할 수 있다.
WebClient의 특징
- 논블로킹(Non-Blocking) I/O를 지원한다.
- 리액티브 스트림(Reactive Stream)의 백 프레셔(Back Pressure)를 지원한다.
- 적은 하드웨어 리소스로 동시성을 지원한다.
- 함수형 API를 지원한다.
- 동기 / 비동기 상호작용을 지원한다.
- 스트리밍을 지원한다.
WebClient 구성(Maven)
- WebFlux는 클라이언트와 서버 간 리액티브 애플리케이션 개발을 지원하기 위해 스프링 프레임워크 5에서 새롭게 추가된 모듈이다.
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webflux</artifactId>
</dependency>
WebClient GET 요청 예제
@Service
public class WebClientService {
public String getName() {
WebClient webClient = WebClient.builder()
.baseUrl("http://localhost:9090")
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.build();
return webClient.get()
.uri("/api/v1/crud-api")
.retrieve()
.bodyToMono(String.class)
.block();
}
public String getNameWithPathVariable() {
WebClient webClient = WebClient.create("http://localhost:9090");
ResponseEntity<String> responseEntity = webClient.get()
.uri(uriBuilder -> uriBuilder.path("/api/v1/crud-api/{name}")
.build("test"))
.retrieve().toEntity(String.class).block();
return responseEntity.getBody();
}
public String getNameWithPathParameter() {
WebClient webClient = WebClient.create("http://localhost:9090");
return webClient.get().uri(uriBuilder -> uriBuilder.path("/api/v1/crud-api")
.queryParam("name", "test")
.build())
.exchangeToMono(clientResponse -> {
if (clientResponse.statusCode().equals(HttpStatus.OK)) {
return clientResponse.bodyToMono(String.class);
} else {
return clientResponse.createException().flatMap(Mono::error);
}
})
.block();
}
}
- getName( ) 메서드는 builder( ) 를 활용해 WebClient를 만드는 방법이다.
- 다른 2개의 메서드는 create( ) 활용하여 WebClient를 생성한다.
- WebClient는 객체를 생성한 후 요청을 전달하는 방식으로 동작한다.
- builder( )를 통해 baseUrl( ) 메서드에서 기본 URL을 설정하고 defaultHeader( ) 메서드로 헤더 값을 설정한다.
- webClient 객체를 이요할 떄는 객체를 생성한 후에 재사용하는 방식으로 구현하는 것이 좋다.
- builder( ) 를 사용할 경우 확장할 수 있는 메서드
- defaultHeader( ) : WebClient의 기본 헤더 설정
- defaultCookie( ) : WebClient의 기본 쿠키 설정
- defaultUriVariable( ) : WebClient의 기본 URI 확장값 설정
- filter( ) : WebClient에서 발생하는 요청에 대한 필터 설정
- webClient 복사해서 사용하는 방법
WebClient webClient = WebClient.create("http://localhost:9090");
WebClient clone = WebClient.mutate().build();
- retrieve( ) 메서드는 bodyToMono( ) 메서드를 통해 리턴 타입을 설정해서 문자열 객체를 받아오게 된다.
- retrieve( ) 대신 exchange( ) 메서드를 사용이 가능한데 지원이 중단되어 exchangeToMono( ) / exchangeToFlux( )를 사용해야한다.
- WebClient는 기본적으로 논블로킹(Non-Blocking) 방식으로 동작하기 때문에 기존에 사용하던 코드의 구조를 블로킹 구조로 바꿔줄 필요가 있다.
WebClient POST 요청 예제
public ResponseEntity<MemberDto> postWithParamAndBody() {
WebClient webClient = WebClient.builder()
.baseUrl("http://localhost:9090")
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.build();
MemberDto memberDto = new MemberDto();
memberDto.setName("test!!");
memberDto.setEmail("test@gmail.com");
memberDto.setOrganization("studio");
return webClient.post().uri(uriBuilder -> uriBuilder.path("/api/v1/crud-api")
.queryParam("name", "test")
.queryParam("email", "test@naver.com")
.queryParam("organization", "test")
.build())
.bodyValue(memberDto)
.retrieve()
.toEntity(MemberDto.class)
.block();
}
public ResponseEntity<MemberDto> postWithHeader() {
WebClient webClient = WebClient.builder()
.baseUrl("http://localhost:9090")
.defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.build();
MemberDto memberDto = new MemberDto();
memberDto.setName("test!!");
memberDto.setEmail("test@gmail.com");
memberDto.setOrganization("studio");
return webClient.post()
.uri(uriBuilder -> uriBuilder.path("/api/v1/crud-api")
.build())
.bodyValue(memberDto)
.header("my-header", "API")
.retrieve()
.toEntity(MemberDto.class)
.block();
}
- POST 방식에서 눈여겨볼 내용은 HTTP 바디 값을 담는 방법과 커스텀 헤더를 추가하는 방법이다.
- webClient에서 post( ) 메서드를 통해 POST 메서드 통신을 정의했고, uri( )는 uriBuilder로 path와 parameter를 설정
- bodyValue( ) 메서드를 통해 HTTP 바디 값을 설정한다.
- HTTP 바디에는 일반적으로 데이터 객체(DTO, VO 등) 파라미터로 전달한다.
- postWithHeader( ) 메서드는 POST 요청을 보낼 때 헤더를 추가해서 보내는 예제이다.
- 일반적으로 임의로 추가한 헤더에는 외부 API를 사용하기 위해 인증된 토큰값을 담아 전달한다.
반응형
'Book > 스프링부트 핵심가이드' 카테고리의 다른 글
스프링 시큐리티(Spring Security)와 JWT (2) | 2023.12.05 |
---|---|
스프링부트를 이용한 서버 간의 통신(of. RestTemplate) (0) | 2023.12.01 |
스프링부트 액추에이터 기능 (0) | 2023.11.30 |
댓글