9 Temmuz 2019 Salı

SpringWebFlux WebClient.Builder Arayüzü

Giriş
Şu satırı dahil ederiz
import org.springframework.web.reactive.function.client.WebClient;
Kullanım
baseUrl()
defaultHeader()
metodları ile değerler atanır. En son olarak ta build() ile bir WebClient nesnesi elde edilir.

Örnek - Generic Kod
Elimizde şöyle bir kod olsun
@Data @JsonInclude(JsonInclude.Include.NON_NULL) public class GenericResponse<T> { private T responseEntity; private GenericError genericError; }
Genel kullanım için yaparız. Burada WebClient.Builder enjekte ediliyor. Daha sonra build() çağrısı ile bir WebClient elde ediliyor. Ve WebClient ile HTTP işlemi yapılıyor.
private final WebClient.Builder webClientBuilder; @Autowired public GenericWebClient(WebClient.Builder webClientBuilder) { this.webClientBuilder = webClientBuilder; } @Retryable( value = {HttpServerErrorException.class, WebClientRequestException.class, WebClientResponseException.class}, maxAttemptsExpression = "${generic.webclient.endpoint.maxAttempts:4}", backoff = @Backoff(delayExpression = "${generic.webclient.endpoint.maxDelay:4000}")) public <T> ResponseEntity<GenericResponse<T>> execute( GenericRequest genericRequest, Object requestEntity) throws HttpServerErrorException, WebClientRequestException, WebClientResponseException { Mono<GenericResponse<T>> response = null; AtomicInteger cnt = new AtomicInteger(1); try { response = this.webClientBuilder.build() .method(genericRequest.getHttpMethod()) .uri(genericRequest.getServiceUrl()) .bodyValue(requestEntity) .retrieve() .bodyToMono(new ParameterizedTypeReference<GenericResponse<T>>() { }) .doOnNext(apiResponse -> process(genericRequest.getServiceUrl(), apiResponse)); } catch (HttpServerErrorException exception) { this.handleHttpServerErrorException(exception); } catch (WebClientRequestException exception) { if (exception.getCause() instanceof ConnectException) { log.error("Retry method called - {}", cnt.getAndIncrement()); log.error("...", exception); throw exception; } } catch (WebClientResponseException exception) { if (exception.getStatusCode().is5xxServerError()) { log.error("...", exception); throw exception; } }

baseUrl metodu
Örnek
Şöyle yaparız
@Value("${rest.UserDetailsService.service.endpoint}")
private String baseUrl;

private WebClient webClient;

@PostConstruct
private void init(){
  this.webClient = WebClient.builder().baseUrl(baseUrl).build();
}
clientConnector metodu
Örnek - ReactorClientHttpConnector
Şöyle yaparız. ReactorClientHttpConnector içine bir tane HttpClient nesnesi alır
import org.springframework.http.client.reactive.ReactorClientHttpConnector; import org.springframework.web.reactive.function.client.WebClient; import reactor.netty.http.client.HttpClient; @Configuration public class WebClientConfig { @Bean public WebClient webClient() { return WebClient.builder() .clientConnector(new ReactorClientHttpConnector(getHttpClient())) .baseUrl("<service-url>") .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .build(); } private HttpClient getHttpClient() { return HttpClient.create() .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10_000) .doOnConnected(conn -> conn .addHandlerLast(new ReadTimeoutHandler(10)) .addHandlerLast(new WriteTimeoutHandler(10))); } }
Örnek - ReactorClientHttpConnector
Şöyle yaparız. ReactorClientHttpConnector içine bir tane HttpClient nesnesi alır
// Build a custom WebClient with specified timeout and default headers WebClient customWebClient = WebClient.builder() .baseUrl("http://example.com") .clientConnector(new ReactorClientHttpConnector( HttpClient.create() .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 2000) // 2 seconds timeout .responseTimeout(Duration.ofSeconds(2)) // Set response timeout .doOnConnected(conn -> conn.addHandlerLast(new ReadTimeoutHandler(2)) // 2 seconds read timeout .addHandlerLast(new WriteTimeoutHandler(2))))) // 2 seconds write timeout // Default header .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .defaultHeader("Another-Header", "Another-Value") // Another default header .build();
Örnek - Mutual TLS
Şöyle yaparız. ReactorClientHttpConnector içine bir tane HttpClient nesnesi alır
// Preparing the SSL context with both trust store and key store SslContext sslContext = SslContextBuilder .forClient() // for demo purposes only! .trustManager(InsecureTrustManagerFactory.INSTANCE) // client certificate and private key .keyManager(new File("path/to/client.crt"), new File("path/to/client.key")) .build(); // Configuring the WebClient with the SSL context WebClient secureWebClient = WebClient.builder() .clientConnector(new ReactorClientHttpConnector(HttpClient.create() .secure(sslContextSpec -> sslContextSpec.sslContext(sslContext)))) .build();

codecs metodu
Bir örnek burada

defaultHeader metodu
Örnek
Şöyle yaparız
public InventoryClient(InventoryClientProperties inventoryClientProperties) { HttpClient httpClient = HttpClient.create() .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000) .doOnConnected(conn -> conn .addHandlerLast(new ReadTimeoutHandler(10)) .addHandlerLast(new WriteTimeoutHandler(10))); retrySpec = Retry .backoff(inventoryClientProperties.getRetry().getMaxAttempts(), inventoryClientProperties.getRetry().getBackoffDuration()) .filter(throwable -> throwable instanceof ExternalCommunicationException) .onRetryExhaustedThrow(this::handleRetryExhaustedError); webClient = WebClient.builder() .baseUrl(inventoryClientProperties.getUrl() + "/books") .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .clientConnector(new ReactorClientHttpConnector(httpClient)) .build(); } ServiceUnavailableException handleRetryExhaustedError(RetryBackoffSpec retryBackoffSpec, RetrySignal retrySignal) { throw new ServiceUnavailableException("communication failed after max retries"); }

filter metodu
Açıklaması şöyle
WebClient supports the use of filters for cross-cutting concerns. These filters can be used to manipulate the request or response, or even to handle concerns like logging, metrics, or authorization.
Örnek
Şöyle yaparız.
WebClient.builder().baseUrl("/").filter(contentTypeInterceptor()).build();
Örnek - ReactorClientHttpConnector
Şöyle yaparız. ReactorClientHttpConnector içine bir tane HttpClient nesnesi alır
// Custom WebClient with a filter WebClient filteredWebClient = WebClient.builder() .baseUrl("http://example.com") .filter((request, next) -> { // Log request data System.out.println("Request: " + request.method() + " " + request.url()); return next.exchange(request).doOnSuccessOrError((response, error) -> { if (response != null) { // Log response data System.out.println("Response Status: " + response.statusCode()); } if (error != null) { // Log error System.out.println("Error: " + error.getMessage()); } }); }) .build();
Açıklaması şöyle
This filter logs the HTTP method and URL for every request made through this WebClient instance, and the status code for every response received. It also logs any error that might occur during the exchange.


Hiç yorum yok:

Yorum Gönder