Spring Webflux에는 reactive, non-blocking하게 HTTP요청을 처리할 수 있도록 WebClient 모듈을 제공
기존의 RestTemplate과 같은 역할이지만, non-blocking하다라는 차이가 있다.
내부적으로 WebClient는 HTTP 클라이언트 라이브러리에 위임하는데, 디폴트로 Reactor Netty의 HttpClient를 사용한다. Reactor Netty외에도, Jetty의 HttpClient를 지원하며, 다른 라이브러리도 ClientHttpConnector에 넣어주면 사용할 수 있다.
Setup the WebClient
create()
- default WebClient
- base URL
this.webClient = WebClient.create(); //or this.webClient = WebClient.create("http://localhost:12345");
this.webClient = WebClient.builder() .baseUrl(properties.getHost()) .defaultHeader("Accept", MediaType.APPLICATION_JSON_VALUE, "Content-Type", MediaType.APPLICATION_JSON_VALUE ).build();
Making calls
public Mono<ReturnedItem> callOne() { return webClient.get() .uri("wait1") .retrieve() .bodyToMono(ReturnedItem.class); } public record ReturnedItem(UUID id, String info) {}
- REST action
- GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS의 helper method 제공됨
- uri()
- 호출 url, WebClient에서 설정한 baseUrl에 append 됨
- retrieve
- 실제 호출을 수행하고 호출을 설정하는 메서드에서 응답을 처리하는 메서드로 변환
- bodyToMono
- 원하는 payload를 제공
Request Body
retrieve()
response body를 가져오는 가장 단순한 방법이다. 오브젝트 stream을 Flux로 받을 수도 있다.
디폴트로, HTTP 응답 코드가 4xx, 5xx로 오면 WebClientResponseException이 발생한다. onStatus() 메소드를 통해 exception을 커스터마징할 수 있다.
Mono<Person> result = client.get() .uri("/persons/{id}", id).accept(MediaType.APPLICATION_JSON) .retrieve() .onStatus(HttpStatus::is4xxServerError, response -> ...) .onStatus(HttpStatus::is5xxServerError, response -> ...) .bodyToMono(Person.class);
exchange()
retrieve()와 동일한 역할을 하면서 ClientResponse 객체의 접근을 가능하게 해 response 처리를 커스터마이징하기 보다 용이합니다.
Mono<Person> result = client.get() .uri("/persons/{id}", id).accept(MediaType.APPLICATION_JSON) .exchange() .flatMap(response -> response.bodyToMono(Person.class));
Mono형태의 객체를 request body에 넣을 수 있다.
Mono<Person> personMono = ... ; Mono<Void> result = client.post() .uri("/persons/{id}", id) .contentType(MediaType.APPLICATION_JSON) .body(personMono, Person.class) .retrieve() .bodyToMono(Void.class);
Flux<Person> personFlux = ... ; Mono<Void> result = client.post() .uri("/persons/{id}", id) .contentType(MediaType.APPLICATION_STREAM_JSON) .body(personFlux, Person.class) .retrieve() .bodyToMono(Void.class);
Mono나 Flux로 감싸지 않는 실제 오브젝트는 syncBody() 메소드로 넣을 수 있다.
Person person = ... ; Mono<Void> result = client.post() .uri("/persons/{id}", id) .contentType(MediaType.APPLICATION_JSON) .syncBody(person) .retrieve() .bodyToMono(Void.class);
form data를 넣고 싶으면 MultiValueMap형태로 body에 넣을 수 있다. 이 경우 자동으로 콘텐트 타입이 ‘application/x-www-form-urlencoded’로 셋팅된다.
MultiValueMap<String, String> formData = ... ; Mono<Void> result = client.post() .uri("/path", id) .syncBody(formData) .retrieve() .bodyToMono(Void.class);
评论
发表评论