Apache Commons AsyncClient - 忽略证书 - SSLPeerUnverifiedException
Apache Commons AsyncClient - Ignore Certificates - SSLPeerUnverifiedException
以为我在我的 Http 客户端中禁用了证书检查,但一直在 SSLPeerUnverifiedException
。
这是我的客户:
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.util.Arrays;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.stream.Stream;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.methods.RequestBuilder;
import org.apache.http.concurrent.FutureCallback;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.entity.BufferedHttpEntity;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.apache.http.impl.nio.client.HttpAsyncClients;
import org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager;
import org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor;
import org.apache.http.message.BasicHeader;
import org.apache.http.nio.reactor.ConnectingIOReactor;
import org.apache.http.nio.reactor.IOReactorException;
import org.apache.http.ssl.SSLContextBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
class ApacheCommonsAsyncClient implements IMakeHttpRequests {
private static final Logger LOGGER = LoggerFactory.getLogger(PaxHttpClient.class);
private static final int MAX_POOL_SIZE = 100;
private static final int MAX_CONN_PER_ROUTE = 10;
private final CloseableHttpAsyncClient httpClient;
ApacheCommonsAsyncClient() {
final RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(5000)
.setConnectionRequestTimeout(5000).setSocketTimeout(0).build();
final Header doNotKeepAlive = new BasicHeader("Connection: keep-alive", "false");
final Header closeConnection = new BasicHeader("Connection", "close");
try {
final SSLContextBuilder sslContextBuilder = new SSLContextBuilder().loadTrustMaterial(null,
new TrustSelfSignedStrategy());
final ConnectingIOReactor ioReactor = new DefaultConnectingIOReactor();
final PoolingNHttpClientConnectionManager cm = new PoolingNHttpClientConnectionManager(ioReactor);
// @formatter:off
this.httpClient = HttpAsyncClients.custom()
.setDefaultRequestConfig(requestConfig)
.setKeepAliveStrategy((httpResponse, httpContext) -> 0)
.setDefaultHeaders(Arrays.asList(doNotKeepAlive, closeConnection))
.setConnectionManager(cm)
.setSSLContext(sslContextBuilder.build())
.setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
.setMaxConnTotal(MAX_POOL_SIZE)
.setMaxConnPerRoute(MAX_CONN_PER_ROUTE)
.build();
// @formatter:on
this.httpClient.start();
} catch (final GeneralSecurityException | IOReactorException e) {
throw new RuntimeException(e);
}
}
}
异常:
java.util.concurrent.ExecutionException: javax.net.ssl.SSLPeerUnverifiedException: Host name '<public-dns>' does not match the certificate subject provided by the peer (CN=*.<domain>.com, O="<org>", L=<location>, ST=<state>, C=<country>)
at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:357)
at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1895)
at com.paxata.performance.App.run(App.java:30)
at com.paxata.performance.Bootstrap.main(Bootstrap.java:43)
Caused by: javax.net.ssl.SSLPeerUnverifiedException: Host name '<public-dns>' does not match the certificate subject provided by the peer (CN=*.<domain>.com, O="<org>", L=<location>, ST=<state>, C=<country>)
at org.apache.http.nio.conn.ssl.SSLIOSessionStrategy.verifySession(SSLIOSessionStrategy.java:208)
at org.apache.http.nio.conn.ssl.SSLIOSessionStrategy.verify(SSLIOSessionStrategy.java:188)
at org.apache.http.nio.reactor.ssl.SSLIOSession.doHandshake(SSLIOSession.java:367)
at org.apache.http.nio.reactor.ssl.SSLIOSession.isAppInputReady(SSLIOSession.java:508)
at org.apache.http.impl.nio.reactor.AbstractIODispatch.inputReady(AbstractIODispatch.java:120)
at org.apache.http.impl.nio.reactor.BaseIOReactor.readable(BaseIOReactor.java:162)
at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvent(AbstractIOReactor.java:337)
at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvents(AbstractIOReactor.java:315)
at org.apache.http.impl.nio.reactor.AbstractIOReactor.execute(AbstractIOReactor.java:276)
at org.apache.http.impl.nio.reactor.BaseIOReactor.execute(BaseIOReactor.java:104)
at org.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor$Worker.run(AbstractMultiworkerIOReactor.java:588)
at java.lang.Thread.run(Thread.java:748)
以及我引入的依赖版本:
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
<version>4.5.5</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>4.4.9</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpasyncclient</artifactId>
<version>4.1.3</version>
</dependency>
传递给构建器的连接管理器实例取代所有连接管理参数,例如 SSL 和池设置。
有两种补救方法。
- 让构建器构造并初始化一个连接管理器
final SSLContextBuilder sslContextBuilder = new SSLContextBuilder().loadTrustMaterial(null,
new TrustSelfSignedStrategy());
this.httpClient = HttpAsyncClients.custom()
.setDefaultRequestConfig(requestConfig)
.setKeepAliveStrategy((httpResponse, httpContext) -> 0)
.setDefaultHeaders(Arrays.asList(doNotKeepAlive, closeConnection))
.setSSLContext(sslContextBuilder.build())
.setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
.setMaxConnTotal(MAX_POOL_SIZE)
.setMaxConnPerRoute(MAX_CONN_PER_ROUTE)
.build();
- 在传递给构建器之前配置连接管理器
final SSLContextBuilder sslContextBuilder = new SSLContextBuilder().loadTrustMaterial(null,
new TrustSelfSignedStrategy());
final PoolingNHttpClientConnectionManager cm = new PoolingNHttpClientConnectionManager(
new DefaultConnectingIOReactor(),
RegistryBuilder.<SchemeIOSessionStrategy>create()
.register("http", NoopIOSessionStrategy.INSTANCE)
.register("https", new SSLIOSessionStrategy(sslContextBuilder.build(), NoopHostnameVerifier.INSTANCE))
.build());
cm.setMaxTotal(MAX_POOL_SIZE);
cm.setDefaultMaxPerRoute(MAX_CONN_PER_ROUTE);
this.httpClient = HttpAsyncClients.custom()
.setDefaultRequestConfig(requestConfig)
.setKeepAliveStrategy((httpResponse, httpContext) -> 0)
.setDefaultHeaders(Arrays.asList(doNotKeepAlive, closeConnection))
.setConnectionManager(cm)
.build();
推荐前者,除非有非常充分的理由选择后者。
PS:您不想禁用连接持久性
以为我在我的 Http 客户端中禁用了证书检查,但一直在 SSLPeerUnverifiedException
。
这是我的客户:
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.util.Arrays;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.stream.Stream;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.methods.RequestBuilder;
import org.apache.http.concurrent.FutureCallback;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.entity.BufferedHttpEntity;
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
import org.apache.http.impl.nio.client.HttpAsyncClients;
import org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager;
import org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor;
import org.apache.http.message.BasicHeader;
import org.apache.http.nio.reactor.ConnectingIOReactor;
import org.apache.http.nio.reactor.IOReactorException;
import org.apache.http.ssl.SSLContextBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
class ApacheCommonsAsyncClient implements IMakeHttpRequests {
private static final Logger LOGGER = LoggerFactory.getLogger(PaxHttpClient.class);
private static final int MAX_POOL_SIZE = 100;
private static final int MAX_CONN_PER_ROUTE = 10;
private final CloseableHttpAsyncClient httpClient;
ApacheCommonsAsyncClient() {
final RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(5000)
.setConnectionRequestTimeout(5000).setSocketTimeout(0).build();
final Header doNotKeepAlive = new BasicHeader("Connection: keep-alive", "false");
final Header closeConnection = new BasicHeader("Connection", "close");
try {
final SSLContextBuilder sslContextBuilder = new SSLContextBuilder().loadTrustMaterial(null,
new TrustSelfSignedStrategy());
final ConnectingIOReactor ioReactor = new DefaultConnectingIOReactor();
final PoolingNHttpClientConnectionManager cm = new PoolingNHttpClientConnectionManager(ioReactor);
// @formatter:off
this.httpClient = HttpAsyncClients.custom()
.setDefaultRequestConfig(requestConfig)
.setKeepAliveStrategy((httpResponse, httpContext) -> 0)
.setDefaultHeaders(Arrays.asList(doNotKeepAlive, closeConnection))
.setConnectionManager(cm)
.setSSLContext(sslContextBuilder.build())
.setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
.setMaxConnTotal(MAX_POOL_SIZE)
.setMaxConnPerRoute(MAX_CONN_PER_ROUTE)
.build();
// @formatter:on
this.httpClient.start();
} catch (final GeneralSecurityException | IOReactorException e) {
throw new RuntimeException(e);
}
}
}
异常:
java.util.concurrent.ExecutionException: javax.net.ssl.SSLPeerUnverifiedException: Host name '<public-dns>' does not match the certificate subject provided by the peer (CN=*.<domain>.com, O="<org>", L=<location>, ST=<state>, C=<country>)
at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:357)
at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1895)
at com.paxata.performance.App.run(App.java:30)
at com.paxata.performance.Bootstrap.main(Bootstrap.java:43)
Caused by: javax.net.ssl.SSLPeerUnverifiedException: Host name '<public-dns>' does not match the certificate subject provided by the peer (CN=*.<domain>.com, O="<org>", L=<location>, ST=<state>, C=<country>)
at org.apache.http.nio.conn.ssl.SSLIOSessionStrategy.verifySession(SSLIOSessionStrategy.java:208)
at org.apache.http.nio.conn.ssl.SSLIOSessionStrategy.verify(SSLIOSessionStrategy.java:188)
at org.apache.http.nio.reactor.ssl.SSLIOSession.doHandshake(SSLIOSession.java:367)
at org.apache.http.nio.reactor.ssl.SSLIOSession.isAppInputReady(SSLIOSession.java:508)
at org.apache.http.impl.nio.reactor.AbstractIODispatch.inputReady(AbstractIODispatch.java:120)
at org.apache.http.impl.nio.reactor.BaseIOReactor.readable(BaseIOReactor.java:162)
at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvent(AbstractIOReactor.java:337)
at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvents(AbstractIOReactor.java:315)
at org.apache.http.impl.nio.reactor.AbstractIOReactor.execute(AbstractIOReactor.java:276)
at org.apache.http.impl.nio.reactor.BaseIOReactor.execute(BaseIOReactor.java:104)
at org.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor$Worker.run(AbstractMultiworkerIOReactor.java:588)
at java.lang.Thread.run(Thread.java:748)
以及我引入的依赖版本:
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
<version>4.5.5</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>4.4.9</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpasyncclient</artifactId>
<version>4.1.3</version>
</dependency>
传递给构建器的连接管理器实例取代所有连接管理参数,例如 SSL 和池设置。
有两种补救方法。
- 让构建器构造并初始化一个连接管理器
final SSLContextBuilder sslContextBuilder = new SSLContextBuilder().loadTrustMaterial(null,
new TrustSelfSignedStrategy());
this.httpClient = HttpAsyncClients.custom()
.setDefaultRequestConfig(requestConfig)
.setKeepAliveStrategy((httpResponse, httpContext) -> 0)
.setDefaultHeaders(Arrays.asList(doNotKeepAlive, closeConnection))
.setSSLContext(sslContextBuilder.build())
.setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
.setMaxConnTotal(MAX_POOL_SIZE)
.setMaxConnPerRoute(MAX_CONN_PER_ROUTE)
.build();
- 在传递给构建器之前配置连接管理器
final SSLContextBuilder sslContextBuilder = new SSLContextBuilder().loadTrustMaterial(null,
new TrustSelfSignedStrategy());
final PoolingNHttpClientConnectionManager cm = new PoolingNHttpClientConnectionManager(
new DefaultConnectingIOReactor(),
RegistryBuilder.<SchemeIOSessionStrategy>create()
.register("http", NoopIOSessionStrategy.INSTANCE)
.register("https", new SSLIOSessionStrategy(sslContextBuilder.build(), NoopHostnameVerifier.INSTANCE))
.build());
cm.setMaxTotal(MAX_POOL_SIZE);
cm.setDefaultMaxPerRoute(MAX_CONN_PER_ROUTE);
this.httpClient = HttpAsyncClients.custom()
.setDefaultRequestConfig(requestConfig)
.setKeepAliveStrategy((httpResponse, httpContext) -> 0)
.setDefaultHeaders(Arrays.asList(doNotKeepAlive, closeConnection))
.setConnectionManager(cm)
.build();
推荐前者,除非有非常充分的理由选择后者。
PS:您不想禁用连接持久性