使用 Apache HttpComponents 通过 Webflux Web 客户端配置 SSL

问题描述 投票:0回答:3

我正在尝试从restTemplate 迁移到webClient。

一切都很好,直到我使用

ClientHttpRequestFactory
到达restTemplate配置。

我将旧代码和新代码粘贴在这里。

------带有restTemplate的旧代码------

private HttpComponentsClientHttpRequestFactory buildRequestFactory() {

    HttpClientBuilder clientBuilder = HttpClientBuilder.create();
    HttpHost proxy = new HttpHost(proxyHost, proxyPort);
    CredentialsProvider credsProvider = new BasicCredentialsProvider();
    credsProvider.setCredentials(new AuthScope(proxyHost, proxyPort),
            new UsernamePasswordCredentials(proxyUser, proxyPassword));
    clientBuilder.useSystemProperties();
    clientBuilder.setProxy(proxy);
    clientBuilder.setDefaultCredentialsProvider(credsProvider);
    clientBuilder.setProxyAuthenticationStrategy(new ProxyAuthenticationStrategy());

    TrustStrategy acceptingTrustStrategy = new TrustStrategy() {
        public boolean isTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
            return true;
        }
    };

    SSLContext sslContext = null;
    try {
        sslContext = org.apache.http.ssl.SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build();
    } catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) {
        throw new ServiceException(GlobalErrorMessage.INTERNAL_SERVER_ERROR);
    }

    SSLConnectionSocketFactory connectionFactory = new SSLConnectionSocketFactory(sslContext, new NoopHostnameVerifier());
    CloseableHttpClient httpClient = clientBuilder
            .setSSLSocketFactory(connectionFactory)
            .setRoutePlanner(new DefaultProxyRoutePlanner(proxy) {
                @Override
                public HttpHost determineProxy(HttpHost target, HttpRequest request, HttpContext context)
                        throws HttpException {
                    if (target.getHostName().equals(noproxy)) {
                        return null;
                    }
                    return super.determineProxy(target, request, context);
                }
            })
            .build();
    HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
    requestFactory.setHttpClient(httpClient);

    return requestFactory;
}

@Bean(name = "gatewayRestTemplate")
public RestTemplate gatewayRestTemplateConfig() {
    RestTemplate restTemplate = new RestTemplate(converters());
    restTemplate.setRequestFactory(buildRequestFactory());
    return restTemplate;
}

------带有 webClient 的新代码------

private ClientHttpConnector buildClientConnector() {
    HttpAsyncClientBuilder clientBuilder = HttpAsyncClients.custom();
    org.apache.hc.core5.http.HttpHost proxy = new org.apache.hc.core5.http.HttpHost(proxyHost, proxyPort);
    org.apache.hc.client5.http.auth.CredentialsProvider credsProvider = new org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider();
    ((org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider) credsProvider).setCredentials(new org.apache.hc.client5.http.auth.AuthScope(proxyHost, proxyPort),
            new org.apache.hc.client5.http.auth.UsernamePasswordCredentials(proxyUser, proxyPassword.toCharArray()));
    clientBuilder.useSystemProperties();
    clientBuilder.setProxy(proxy);
    clientBuilder.setDefaultCredentialsProvider(credsProvider);
    clientBuilder.setProxyAuthenticationStrategy(new DefaultAuthenticationStrategy());

    TrustStrategy acceptingTrustStrategy = new TrustStrategy() {
        public boolean isTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
            return true;
        }
    };

    SSLContext sslContext = null;
    try {
        sslContext = org.apache.http.ssl.SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build();
    } catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) {
        throw new ServiceException(GlobalErrorMessage.INTERNAL_SERVER_ERROR);
    }

    org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory connectionFactory =
            new org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory(sslContext, new NoopHostnameVerifier());

    org.apache.hc.core5.http.config.Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder
            // .<org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory>create().register("https", connectionFactory)
            .<ConnectionSocketFactory>create().register("https", connectionFactory)
            // .register("http", new PlainConnectionSocketFactory())
            .build();
    PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);

    CloseableHttpAsyncClient client = clientBuilder
            .setConnectionManager((AsyncClientConnectionManager) connectionManager)
            .setRoutePlanner(new org.apache.hc.client5.http.impl.routing.DefaultProxyRoutePlanner(proxy) {
                @Override
                protected org.apache.hc.core5.http.HttpHost determineProxy(org.apache.hc.core5.http.HttpHost target, org.apache.hc.core5.http.protocol.HttpContext context) throws org.apache.hc.core5.http.HttpException {
                    if (target.getHostName().equals(noproxy)) {
                        return null;
                    }
                    return super.determineProxy(target, context);
                }
            })
            .build();
    ClientHttpConnector connector = new HttpComponentsClientHttpConnector(client);
    return connector;
}

@Primary
@Bean(name = "defaultWebClient")
public WebClient defaultWebClientConfig() {
    WebClient webClient = WebClient.builder()
            .clientConnector(buildClientConnector())
            .build();
    return webClient;
}

当我运行该项目时,我收到此异常:

Caused by: java.lang.ClassCastException: class org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager cannot be cast to class org.apache.hc.client5.http.nio.AsyncClientConnectionManager (org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager and org.apache.hc.client5.http.nio.AsyncClientConnectionManager are in unnamed module of loader 'app')

spring-boot spring-webclient apache-httpcomponents webflux apache-httpclient-5.x
3个回答
2
投票

基于迁移到 Apache HttpClient 5.0 异步 API,我解决了我的问题。这个想法是在设置

ClientTlsStrategyBuilder
时使用
sslContext

private ClientHttpConnector buildClientConnector() {
    HttpAsyncClientBuilder clientBuilder = HttpAsyncClients.custom();
    org.apache.hc.core5.http.HttpHost proxy = new org.apache.hc.core5.http.HttpHost(proxyHost, proxyPort);
    org.apache.hc.client5.http.auth.CredentialsProvider credsProvider = new org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider();
    ((org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider) credsProvider).setCredentials(new org.apache.hc.client5.http.auth.AuthScope(proxyHost, proxyPort),
            new org.apache.hc.client5.http.auth.UsernamePasswordCredentials(proxyUser, proxyPassword.toCharArray()));
    clientBuilder.useSystemProperties();
    clientBuilder.setProxy(proxy);
    clientBuilder.setDefaultCredentialsProvider(credsProvider);
    clientBuilder.setProxyAuthenticationStrategy(new DefaultAuthenticationStrategy());
    TrustStrategy acceptingTrustStrategy = (x509Certificates, s) -> true;
    SSLContext sslContext;
    try {
        sslContext = org.apache.http.ssl.SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build();
    } catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) {
        throw new ServiceException(GlobalErrorMessage.INTERNAL_SERVER_ERROR);
    }
    PoolingAsyncClientConnectionManager connectionManager = PoolingAsyncClientConnectionManagerBuilder.create()
            .setTlsStrategy(ClientTlsStrategyBuilder.create()
                    .setSslContext(sslContext)
                    .setHostnameVerifier(new NoopHostnameVerifier())
                    .build())
            .build();

    CloseableHttpAsyncClient client = clientBuilder
            .setConnectionManager(connectionManager)
            .setRoutePlanner(new org.apache.hc.client5.http.impl.routing.DefaultProxyRoutePlanner(proxy) {
                @Override
                protected org.apache.hc.core5.http.HttpHost determineProxy(org.apache.hc.core5.http.HttpHost target, org.apache.hc.core5.http.protocol.HttpContext context) throws org.apache.hc.core5.http.HttpException {
                    if (target.getHostName().equals(noproxy)) {
                        return null;
                    }
                    return super.determineProxy(target, context);
                }
            })
            .build();
    ClientHttpConnector connector = new HttpComponentsClientHttpConnector(client);
    return connector;
}

@Primary
@Bean(name = "defaultWebClient")
public WebClient defaultWebClientConfig() {
    WebClient webClient = WebClient.builder()
        .clientConnector(buildClientConnector())
        .build();
    return webClient;
}

0
投票

谢谢您的分享。 我想问我们如何在新的实现中使用以下部分代码: org.apache.hc.core5.http.config.Registry socketFactoryRegistry =RegistryBuilder // .create().register("https", connectionFactory) .create().register("https",connectionFactory) // .register("http", new PlainConnectionSocketFactory()) 。建造(); 您在问题中提到了我们可以在新实现中的此代码部分中注册 hhtp 和 https 的问题 等待您的回复。 致以诚挚的问候。


-1
投票

如果您想使用HttpClient连接器。请使用下面的代码 网络客户端。上面的答案都不起作用,下面的解决方案是 对我来说工作得很好。

SslContext sslContext = SslContextBuilder
            .forClient()
            .trustManager(InsecureTrustManagerFactory.INSTANCE)
            .build();

  HttpClient httpClient = HttpClient.create().secure(t -> 
    t.sslContext(sslContext) );
    WebClient webClient =  WebClient.builder()
             .baseUrl("any-url")
            .clientConnector(new ReactorClientHttpConnector(httpClient))
            .build();
© www.soinside.com 2019 - 2024. All rights reserved.