使用Apache HttpComponents为Webflux WebClient配置SSL出现类转换异常
问题原因
你使用的PoolingHttpClientConnectionManager是Apache HttpClient5中用于同步阻塞IO场景的连接管理器,归属org.apache.hc.client5.http.impl.io包;而WebClient依赖的是异步非阻塞的HttpAsyncClient,要求连接管理器必须实现org.apache.hc.client5.http.nio.AsyncClientConnectionManager接口,二者类型不匹配,因此强转抛出异常。
解决方案
替换为异步场景专用的连接管理器PoolingAsyncClientConnectionManager,同时适配异步SSL连接工厂配置,修正后的代码如下:
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 = 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配置TLS参数 org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory sslSocketFactory = new org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory(sslContext, new NoopHostnameVerifier()); // 构造异步连接管理器 PoolingAsyncClientConnectionManager connectionManager = PoolingAsyncClientConnectionManagerBuilder.create() .setSSLSocketFactory(sslSocketFactory) .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(); client.start(); // 异步客户端需要手动启动 ClientHttpConnector connector = new HttpComponentsClientHttpConnector(client); return connector; }
额外注意点
- 异步HttpAsyncClient构造完成后必须调用
start()方法启动,否则会抛出客户端未运行的异常 - 无需手动强转连接管理器类型,
PoolingAsyncClientConnectionManager本身已经实现了AsyncClientConnectionManager接口
内容的提问来源于stack exchange,提问作者Amir Choubani
相关产品推荐
相关产品推荐

