Solucionado (ver solução)
Solucionado
(ver solução)
6
respostas

Erros utilizando webflux para consumir apis

Olá pessoal estou consumindo uma api externa com Webflux e em alguns momentos recebo algumas exceções abaixo:

WebClientRequestException : General SSLEngine problem; nested exception is javax.net.ssl.SSLHandshakeException: General SSLEngine problem

SSLHandshakeException : The connection observed an error javax.net.ssl.SSLHandshakeException: General SSLEngine problem

Criei o webclient desta forma:

@Bean
    public WebClient createWebClient2() {
        return WebClient.builder()                
                .baseUrl("https://myapiconsume")                
                .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)                                
                .build();
    }

e faço a chamada assim:

                                                this.webClientConfiguration
                                                      .createWebClient2()                                                
                                                      .post()
                                                      .uri(uri)                                                
                                                      .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
                                                      .accept(MediaType.APPLICATION_JSON)
                                                      .header(HttpHeaders.AUTHORIZATION, "Basic "+basicAuthHeader)
                                                      .header(HttpHeaders.CACHE_CONTROL, "no-cache")                                                
                                                      .body(Mono.just(request),SmsRequestHeaderDto.class)
                                                      .retrieve()
                                                      .bodyToMono(SmsResponseHeaderDto.class)
                                                      .block();        

para tentar evitar este problema tentei criar o webclient conforme abaixo mas ainda recebo estas exceções

@Bean
    public WebClient createWebClient2() {

        HttpClient httpClient = HttpClient.create().secure(spec ->
           {
            try {
                spec.sslContext(SslContextBuilder.forClient().build());
            } catch (SSLException e) {
                log.error("Erro em sslContext "+e.getMessage()+"\n");
                e.printStackTrace();
            }
        });



        //https://github.com/reactor/reactor-netty/issues/1774
                ConnectionProvider provider = ConnectionProvider.builder("fixed")
                                                                .maxConnections(500)
                                                                .maxIdleTime(Duration.ofSeconds(20))
                                                                .maxLifeTime(Duration.ofSeconds(60))
                                                                .pendingAcquireTimeout(Duration.ofSeconds(60))
                                                                .evictInBackground(Duration.ofSeconds(120)).build();                

        return WebClient
                .builder()               
                .clientConnector(new ReactorClientHttpConnector(httpClient.create(provider)))
                 .baseUrl("https://myapiconsume")
                 .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)            
                 .build();
    }

Exsite alguma forma de contornar isso usando o webclient?

6 respostas

Oi Marcos,

Parece ser problema por conta da API que você está consumindo utilizar um certificado auto assinado.

Tem duas opções para você testar nesse cenário:

return WebClient.builder()
    .clientConnector(new ReactorClientHttpConnector(options -> {
        options.poolResources(PoolResources.fixed("httpPool")).compression(true);
})).build();
SslContext sslContext = SslContextBuilder
    .forClient()
    .trustManager(InsecureTrustManagerFactory.INSTANCE)
    .build();

ClientHttpConnector httpConnector = HttpClient.create().secure(t -> t.sslContext(sslContext));

return WebClient.builder().clientConnector(httpConnector).build();

Oi Rodrigo obrjgado pelo retorno, ao tentar implementar os 2 cenários tive as situações abaixo:

Cenário 1 : ao fazer extamente como informado retorna este erro no compilador The constructor ReactorClientHttpConnector((<no type> options) -> {}) is undefined

Insira aqui a descrição dessa imagem para ajudar na acessibilidade

Cenário 2 : ao tentar implementar o cenário 2 ele pede para reailzar um cast e circular o código com try/cat ao realizar isso e compilar é gerada a exceção abaixo

SslContext sslContext;
        ClientHttpConnector httpConnector = null;
        try {
            sslContext = SslContextBuilder
                    .forClient()
                    .trustManager(InsecureTrustManagerFactory.INSTANCE)
                    .build();


             httpConnector = (ClientHttpConnector) HttpClient.create().secure(t -> t.sslContext(sslContext));




        } catch (SSLException e) {
            log.error("SSLException -createWebClient2 "+e.getMessage()+" "+e.getCause());
            e.printStackTrace();
        }

            return WebClient.builder()
                    .clientConnector(httpConnector)
                    .baseUrl("https://my_url_consumes")
                     .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)        
                    .build();

Caused by: java.lang.ClassCastException: reactor.netty.http.client.HttpClientConnect cannot be cast to org.springframework.http.client.reactive.ClientHttpConnector

No código do segundo exemplo é um problema de import de classes.

Você deve ter improtado a classe HttpClientConnect do pacote incorreto e por isso deu ClassCastException.

Estou utilizando estas importações na classe

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.client.reactive.ClientHttpConnector;
import org.springframework.web.reactive.function.client.WebClient;

import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
import lombok.extern.slf4j.Slf4j;
import reactor.netty.http.client.HttpClient;

Devo adicionar mais alguma ou alguma outra dependência?

Oi Rodrigo, Sabe de alguma documentação que posso consultar?

solução!

Entrei em contato com o mantenedor da API e recebi um novo endpoint, neste caso não recebi erros utilizando o webflux.