Spring/스프링으로 시작하는 리액티브 프로그래밍

[Spring WebFlux] WebClient

꾸준함. 2024. 10. 7. 18:57

WebClient

  • 비동기적이고 non-blocking 방식으로 HTTP 요청을 처리할 수 있는 클라이언트
  • 전통적인 Spring MVC의 RestTemplate의 대안으로 Spring 5부터 지원하는 non-blocking HTTP 요청을 위한 리액티브 웹 클라이언트로서 함수형 기반의 향상된 API 제공
    • 비동기적 호출 외에도 block() 메서드를 사용하여 동기적으로 데이터를 받을 수 있지만 WebFlux 환경에서는 가능한 비동기 방식으로 사용하는 것이 성능에 유리

 

  • WebFlux 환경에서의 고성능, 비동기적 애플리케이션 개발을 위해 설계됐으며 기본 HTTP 클라이언트 라이브러리는 Reactor Netty
  • WebClient는 Mono와 Flux를 지원하여, 리액티브 스트림을 통해 데이터를 처리
    • Mono는 하나의 요소를 반환할 때 사용
    • Flux는 여러 요소를 처리할 때 사용

 

WebClient  코드 예시 및 사용법

  • Spring에서 지원하는 ApplicationRunner를 이용해 도서 정보 샘플 애플리케이션이 실행되는 시점에 총 네 번의 HTTP 요청을 전송하도록 설정

 

 

1. exampleWebClient01 메서드 설명

  • 테스트 대상인 BookRouter의 POST()로 전송할 request body를 작성
  • WebClient.create() 메서드를 통해 WebClient 인터페이스의 구현 객체 생성
  • post() 메서드를 통해 HTTP 메서드 타입을 POST로 지정
  • uri() 메서드로 request를 전송할 URI 지정
  • bodyValue() 메서드로 request body를 설정하며 bodyValue() 메서드는 body(BodyInserter)의 단축 메서드
  • retrieve() 메서드는 응답을 어떤 형태로 얻을지에 대한 프로세스의 시작을 선언하는 역할
  • toEntity(Void.class) 메서드는 파라미터로 주어진 클래스의 형태로 변환한 response body가 포함된 ResponseEntity 객체를 반환
    • BookHandler의 createMember() 메서드가 반환하는 ServerResponse에 body 데이터가 추가되지 않기 때문에 toEntity()의 파라미터는 Void.class가 됨

 

  • 최종 응답으로 전달받은 Mono<ResponseEntity<Void>>를 구독하여 응답으로 전달받은 status code와 location header 정보를 로그로 출력

 

2. exampleWebClient02 메서드 설명

  • 테스트 대상인 BookRouter의 PATCH()로 전송할 request body를 작성
  • WebClient.create(baseUrl) 메서드를 통해 WebClient 인터페이스의 구현 객체 생성
  • patch() 메서드를 통해 HTTP 메서드 타입을 PATCH로 지정
  • uri() 메서드로 요청을 전송할 URI를 지정하며 path variable이 포함된 URI의 경우 Varargs의 형태로 path variable 값 전달
  • bodyToMono()를 통해 response body를 파라미터로 전달된 타입의 객체로 디코딩

 

3. exampleWebClient03 메서드 설명

  • get() 메서드를 통해 HTTP 메서드 타입을 GET으로 지정
  • uri() 메서드로 요청을 전송할 URI를 지정하며 uriBuilder를 통해 path variable의 값을 포함한 URI를 생성

 

4. exampleWebClient04 메서드 설명

  • uri() 메서드로 요청을 전송할 URI를 지정하며 uriBuilder의 queryParam() 메서드를 이용해 페이지네이션을 위한 쿼리 파라미터인 page와 size의 값을 포함한 URI 생성
  • bodyToFlux()를 통해 response body를 파라미터로 전달된 타입의 객체로 디코딩
    • bodyToFlux()는 bodyToMoo()와 달리 자바 컬렉션 타입의 response body 수신

 

WebClient Connection Timeout 설정

  • WebClient는 특정 서버 엔진의 HTTP Client Connector 설정을 통해 HTTP Connection에 대한 timeout을 설정 가능


 

코드 설명

  • option() 메서드로 Connection 설정을 위한 HTTP Connection이 연결되기까지의 시간인 timeout 시간 설정
  • responseTimeout() 메서드로 응답을 수신하기까지의 Timeout 시간 설정
  • doOnConnected()의 파라미터로 전달되는 람다 표현식을 통해 Connection이 연결된 이후에 수행할 동작 정의
    • 특정 시간 동안 읽을 수 있는 데이터가 없을 경우 ReadTimeoutException 예외를 발생시키는 ReadTimeoutHandler 등록
    • 특정 시간 동안 쓰기 작업을 종료할 수 없을 경우 WriteTimeoutException을 발생시키는 WriteTimeoutHandler 등록

 

  • WebClient의 객체는 Builder 패턴을 통해서도 생성할 수 있는데 이 경우 clientConnector() 메서드를 이용해 앞에서 설정한 서버 엔진의 HTTP Client Connector 설정
    • 여기서는 Reactor Netty에서 제공하는 HttpClient 객체를 생성자 파라미터로 가지는 ReactorClientHttpConnector를 설정

 

exchangeToMono()를 사용한 응답 디코딩

  • retrieve() 대신에 exchangeToMono()나 exchangeToFlux() 메서드를 이용하면 response를 사용자의 요구 조건에 맞게 제어 가능


 

코드 설명

  • exchangeToMono()를 통해 응답을 수신한 다음 HttpStatus가 CREATED이면 ResponseEntity를 반환하고 그 외에는 Exception을 던지도록 처리
  • ClientResponse의 createException() 메서드는 request/response 정보를 포함한 WebClientResponseException 생성

 

참고

  • 스프링으로 시작하는 리액티브 프로그래밍 (황정식 저자)

 

반응형