跳至主要内容

WebClient

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");

builder
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);


[https://dreamchaser3.tistory.com/11](https://dreamchaser3.tistory.com/11] [https://tanzu.vmware.com/developer/guides/spring-webclient-gs/](https://tanzu.vmware.com/developer/guides/spring-webclient-gs/) [https://wedul.site/670](https://wedul.site/670) [https://lts0606.tistory.com/305](https://lts0606.tistory.com/305) [https://www.cognizantsoftvision.com/blog/getting-started-with-reactive-spring-spring-webflux/](https://www.cognizantsoftvision.com/blog/getting-started-with-reactive-spring-spring-webflux/)

评论

此博客中的热门博文

Pandas Plot

pandas.DataFrame.plot.bar import matplotlib.pyplot as plt import pandas as pd import numpy as np df = pd.DataFrame(np.random.rand(5, 4).round(1),                   index=['snail', 'pig', 'elephant','rabbit', 'giraffe'],                   columns=pd.Index(['speed', 'lifespan', 'active', 'cuite'],                   name='Genus')) ax = df.plot(kind='bar',figsize=(10,4), rot = 0) plt.show() ==> output in Pycharm

Spring Cache

Cache 추상화 이해하기 핵심부분에서 추상화는 Java method에 캐싱을 적용함으로써 캐시에 보관된 정보로 메서드의 실행 횟수를 줄여준다. 즉 대상 메서드가 실행될때마다 추상화가 해당 메서드가 같은 인자로 이미 실행되었는 확인하는 캐싱 동작을 적용한다. 해당 데이터가 존재한다면 메서드를 실행하지 않고 결과를 반환하고 존재하지 않는다면 메서드를 실행하고 그 결과를 캐싱한 뒤에 사용자에게 반환해서 다음번 호출시에 사용 할 수 있게 한다. Spring cache는 cache 추상화를 지원하는데 EhCache, Redis, Couchbase 등 캐시 저장소와 빠르게 연동하여 bean으로 설정 할 수 있도록 도와준다. 선언적인 어노테이션 기반의 캐싱 @Cacheable  메소드에 지정 가능하고 지정된 메서드의 캐시 설정에 따라 데이터가 한번 생성되면 데이터가 캐싱되며, 다음 호출 시에 캐시에 저장된 데이터가 리턴된다. @Cacheable 설정 옵션은 다음과 같다. value 캐싱 공간의 대표 명칭 key Spring Expression Language(SpEl)으로 key생성을 지정  지정하지 않으면 모든 파라미터를 조합한 해시코드 값을 키로 생성 condition 조건부 캐싱. SpEL로 지정하고 표현식이 true면 메서드를 캐시 사용가능한 SpEL evaluation context 이름 위치 설명 예시 methodName root object 호출되는 메서드의 이름 #root.methodName method root object 호출되는 메서드 #root.method.name target root object 호출되는 대상 객체 #root.target targetClass root object 호출되는 대상 클래스 #root.targetClass args root object 대상을 호출하는데 사용한 인자(배열) #root.args[0] caches root object 현재 실행된 메서드 캐시의 컬렉션 #root.caches[0].name a...

R 데이터 타입

R에서의 데이터 타입 기본형은 Vector 이다. 자료형은 다음과 같다. Vector List Matrix Array DataFrame Vector 정의 다른 언어의 배열과 비슷하고, 한 가지의 스칼라 데이터타입의 데이터들을 저장할 수 있다.       (ex, 숫자만 저장하는 배열/문자열만 저장하는 배열/ a <- 1/ a <- "hello") 슬라이스(Slice)를 제공한다.        Slice란? 배열의 일부를 잘라내고 이를 다시 배열로 다루는 개념 생성 c()함수 안에 원하는 인자들을 나열 > x <- c(1, 2, 3) > x [1] 1 2 3  다음과  x <- c(1, 2, 3)부분에 괄호로 코드를 묶으면 실행된 결과값이 출력된다.        ※ 괄호로 코드를 묶으면 괄호안의 문장을 수행하고 그 결과 값을 화면에 출력 > ( x <- c(1, 2, 3) ) [1] 1 2 3 데이터 접근 인덱스로 데이터에 접근할 수 있고 인덱스는 0이 아닌 1부터 시작한다. 접근 문법 x[n]: vector x의 n번째 요소 x[-n]: vector x에서 n번째 요소를 제외한 나머지를 반환 > x <- c("a", "b", "c") > x[-1] [1] "b" "c" x[idx_vector]: idx_vector에 지정된 요소를 얻어옴. idx_vector는 색인을 표현하는 숫자 vector이다. > x <- c("a", "b", "c") > x[c(1, 2)] [1] "a" "b" x[start:end]: start부터 end까지의 값을 반환, 반환 값은 start위치의 값과...