com.aliyun.httpcomponent.httpclient.ApacheAsyncHttpClientBuilder Maven / Gradle / Ivy
The newest version!
package com.aliyun.httpcomponent.httpclient;
import com.aliyun.core.http.HttpClient;
import com.aliyun.core.http.ProxyOptions;
import com.aliyun.core.logging.ClientLogger;
import com.aliyun.core.utils.Configuration;
import com.aliyun.httpcomponent.httpclient.implementation.CompositeX509TrustManager;
import com.aliyun.httpcomponent.httpclient.implementation.SdkConnectionKeepAliveStrategy;
import com.aliyun.apache.hc.client5.http.ConnectionKeepAliveStrategy;
import com.aliyun.apache.hc.client5.http.auth.AuthScope;
import com.aliyun.apache.hc.client5.http.auth.CredentialsProvider;
import com.aliyun.apache.hc.client5.http.config.RequestConfig;
import com.aliyun.apache.hc.client5.http.impl.async.HttpAsyncClientBuilder;
import com.aliyun.apache.hc.client5.http.impl.async.HttpAsyncClients;
import com.aliyun.apache.hc.client5.http.impl.auth.CredentialsProviderBuilder;
import com.aliyun.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManager;
import com.aliyun.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder;
import com.aliyun.apache.hc.client5.http.ssl.ClientTlsStrategyBuilder;
import com.aliyun.apache.hc.client5.http.ssl.DefaultHostnameVerifier;
import com.aliyun.apache.hc.client5.http.ssl.NoopHostnameVerifier;
import com.aliyun.apache.hc.core5.http.HttpHost;
import com.aliyun.apache.hc.core5.http.impl.DefaultConnectionReuseStrategy;
import com.aliyun.apache.hc.core5.http.nio.ssl.TlsStrategy;
import com.aliyun.apache.hc.core5.reactor.IOReactorConfig;
import com.aliyun.apache.hc.core5.util.Timeout;
import javax.net.ssl.*;
import java.net.*;
import java.security.KeyStore;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
public class ApacheAsyncHttpClientBuilder {
private final ClientLogger logger = new ClientLogger(ApacheAsyncHttpClientBuilder.class);
private HttpAsyncClientBuilder httpAsyncClientBuilder;
private Duration connectionTimeout;
private Duration responseTimeout;
private Duration maxIdleTimeOut;
private Duration keepAlive;
private int maxConnections = 128;
private int maxConnectionsPerRoute = 128;
private Duration connectRequestTimeout;
private ProxyOptions proxyOptions = null;
private Configuration configuration;
private static final long DEFAULT_TIMEOUT = TimeUnit.SECONDS.toMillis(20);
private static final long DEFAULT_KEEP_ALIVE = TimeUnit.SECONDS.toMillis(20);
private static final long DEFAULT_MAX_CONN_TIMEOUT = TimeUnit.SECONDS.toMillis(10);
private static final long DEFAULT_MAX_RESPONSE_TIMEOUT = TimeUnit.SECONDS.toMillis(20);
private static final long DEFAULT_MINIMUM_TIMEOUT = TimeUnit.MILLISECONDS.toMillis(1);
private static final long DEFAULT_CONNECT_REQUEST_TIMEOUT = TimeUnit.SECONDS.toMillis(30);
private static final long DEFAULT_MAX_IDLE_TIMEOUT = TimeUnit.SECONDS.toMillis(30);
private X509TrustManager[] x509TrustManagers = null;
private KeyManager[] keyManagers = null;
private HostnameVerifier hostnameVerifier = null;
private boolean ignoreSSL = false;
public ApacheAsyncHttpClientBuilder() {
this.httpAsyncClientBuilder = HttpAsyncClients.custom();
}
public ApacheAsyncHttpClientBuilder(HttpAsyncClientBuilder httpAsyncClientBuilder) {
this.httpAsyncClientBuilder = Objects.requireNonNull(httpAsyncClientBuilder, "'httpAsyncClientBuilder' cannot be null.");
}
public ApacheAsyncHttpClientBuilder connectionTimeout(Duration connectionTimeout) {
// setConnectionTimeout can be null
this.connectionTimeout = connectionTimeout;
return this;
}
public ApacheAsyncHttpClientBuilder responseTimeout(Duration responseTimeout) {
this.responseTimeout = responseTimeout;
return this;
}
public ApacheAsyncHttpClientBuilder maxIdleTimeOut(Duration maxIdleTimeOut) {
this.maxIdleTimeOut = maxIdleTimeOut;
return this;
}
public ApacheAsyncHttpClientBuilder keepAlive(Duration keepAlive) {
this.keepAlive = keepAlive;
return this;
}
public ApacheAsyncHttpClientBuilder maxConnections(int maxConnections) {
this.maxConnections = maxConnections;
return this;
}
public ApacheAsyncHttpClientBuilder maxConnectionsPerRoute(int maxConnectionsPerRoute) {
this.maxConnectionsPerRoute = maxConnectionsPerRoute;
return this;
}
public ApacheAsyncHttpClientBuilder connectRequestTimeout(Duration connectRequestTimeout) {
this.connectRequestTimeout = connectRequestTimeout;
return this;
}
public ApacheAsyncHttpClientBuilder proxy(ProxyOptions proxyOptions) {
this.proxyOptions = proxyOptions;
return this;
}
public ApacheAsyncHttpClientBuilder configuration(Configuration configuration) {
this.configuration = configuration;
return this;
}
public ApacheAsyncHttpClientBuilder x509TrustManagers(X509TrustManager[] x509TrustManagers) {
this.x509TrustManagers = x509TrustManagers;
return this;
}
public ApacheAsyncHttpClientBuilder keyManagers(KeyManager[] keyManagers) {
this.keyManagers = keyManagers;
return this;
}
public ApacheAsyncHttpClientBuilder hostnameVerifier(HostnameVerifier hostnameVerifier) {
this.hostnameVerifier = hostnameVerifier;
return this;
}
public ApacheAsyncHttpClientBuilder ignoreSSL(boolean ignoreSSL) {
this.ignoreSSL = ignoreSSL;
return this;
}
public HttpClient build() {
// requestConfig
httpAsyncClientBuilder.setDefaultRequestConfig(defaultRequestConfig());
// connectionManager config
PoolingAsyncClientConnectionManager cm = connectionPoolConfig();
httpAsyncClientBuilder.setConnectionManager(cm);
// proxy
Configuration buildConfiguration = (configuration == null)
? Configuration.getGlobalConfiguration()
: configuration;
if (proxyOptions == null && buildConfiguration != Configuration.NONE)
proxyOptions = ProxyOptions.fromConfiguration(buildConfiguration);
if (proxyOptions != null) {
InetSocketAddress inetSocketAddress = proxyOptions.getAddress();
ProxyOptions.Type type = proxyOptions.getType();
switch (type) {
case SOCKS4:
case SOCKS5:
IOReactorConfig.Builder config = IOReactorConfig.custom()
.setSocksProxyAddress(inetSocketAddress);
if (proxyOptions.getUsername() != null) {
config.setSocksProxyUsername(proxyOptions.getUsername())
.setSocksProxyPassword(proxyOptions.getPassword());
}
httpAsyncClientBuilder.setIOReactorConfig(config.build());
break;
default:
httpAsyncClientBuilder.setProxy(new HttpHost(
proxyOptions.getScheme(),
inetSocketAddress.getAddress(),
inetSocketAddress.getHostString(),
inetSocketAddress.getPort()
));
}
if (proxyOptions.getUsername() != null) {
CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
.add(new AuthScope(proxyOptions.getAddress().getHostString(),
proxyOptions.getAddress().getPort()),
proxyOptions.getUsername(),
proxyOptions.getPassword().toCharArray())
.build();
httpAsyncClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
}
// httpAsyncClientBuilder.setRoutePlanner(new SdkProxyRoutePlanner(
// proxyOptions.getScheme(),
// proxyOptions.getAddress(),
// proxyOptions.getNonProxyHosts()));
}
// httpAsyncClientBuilder
httpAsyncClientBuilder
// Connection reuse policy, i.e. whether it can keepAlive
.setConnectionReuseStrategy(DefaultConnectionReuseStrategy.INSTANCE)
// Set how long a connection can remain idle before it is reused, maximum idle time
.setKeepAliveStrategy(buildKeepAliveStrategy())
// Set the connections in the connection pool to clear the maximum idle time using a background thread
.evictIdleConnections(getTimeoutMillis(this.maxIdleTimeOut, "idle"))
// Set up to use background threads to clear expired connections
.evictExpiredConnections()
// Disable redirects
.disableRedirectHandling()
// Disable reconnect policy
.disableAutomaticRetries()
// SDK will set the user agent header in the pipeline. Don't let Apache waste time
.setUserAgent("");
return new ApacheAsyncHttpClient(httpAsyncClientBuilder.build(),
getTimeoutMillis(this.connectionTimeout, "connect"),
this.keepAlive == null ? DEFAULT_KEEP_ALIVE : this.keepAlive.toMillis());
}
private PoolingAsyncClientConnectionManager connectionPoolConfig() {
// set TrustManager
PoolingAsyncClientConnectionManagerBuilder cmb = PoolingAsyncClientConnectionManagerBuilder.create();
List trustManagerList = new ArrayList();
X509TrustManager[] trustManagers = this.x509TrustManagers;
if (null != trustManagers) {
trustManagerList.addAll(Arrays.asList(trustManagers));
}
TrustManagerFactory tmf = null;
try {
// get trustManager using default certification from jdk
tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init((KeyStore) null);
trustManagerList.addAll(Arrays.asList(tmf.getTrustManagers()));
} catch (Exception e) {
throw logger.logExceptionAsError(new RuntimeException(e));
}
final List finalTrustManagerList = new ArrayList();
for (TrustManager tm : trustManagerList) {
if (tm instanceof X509TrustManager) {
finalTrustManagerList.add((X509TrustManager) tm);
}
}
CompositeX509TrustManager compositeX509TrustManager = new CompositeX509TrustManager(finalTrustManagerList);
compositeX509TrustManager.setIgnoreSSLCert(this.ignoreSSL);
// set KeyManager
KeyManager[] keyManagers = null;
if (this.keyManagers != null) {
keyManagers = this.keyManagers;
}
// Generate SSLContext by TrustManager and KeyManager
SSLContext sslContext = null;
try {
sslContext = SSLContext.getInstance("TLS");
sslContext.init(keyManagers, new TrustManager[]{compositeX509TrustManager}, null);
} catch (Exception e) {
throw logger.logExceptionAsError(new RuntimeException(e));
}
// set HostnameVerifier
HostnameVerifier hostnameVerifier = null;
if (this.ignoreSSL) {
hostnameVerifier = new NoopHostnameVerifier();
} else if (this.hostnameVerifier != null) {
hostnameVerifier = this.hostnameVerifier;
} else {
hostnameVerifier = new DefaultHostnameVerifier();
}
// set connection pool TlsStrategy
TlsStrategy tlsStrategy = ClientTlsStrategyBuilder
.create()
.setSslContext(sslContext)
.setHostnameVerifier(hostnameVerifier)
.build();
cmb.setTlsStrategy(tlsStrategy);
// Set the number of connection pool connections and generate a connection manager
PoolingAsyncClientConnectionManager cm = cmb
// Specify the maximum total connection value
.setMaxConnTotal(getMaxConnTotal(this.maxConnections))
// Specify the maximum connection value for each route
.setMaxConnPerRoute(getMaxConnTotal(this.maxConnectionsPerRoute))
.build();
return cm;
}
private RequestConfig defaultRequestConfig() {
RequestConfig.Builder requestConfigBuilder = RequestConfig.custom()
.setConnectionRequestTimeout(getTimeoutMillis(this.connectRequestTimeout, "connectionRequest"))
.setConnectTimeout(getTimeoutMillis(this.connectionTimeout, "connect"))
.setResponseTimeout(getTimeoutMillis(this.responseTimeout, "response"))
.setDefaultKeepAlive(this.keepAlive == null ? DEFAULT_KEEP_ALIVE : this.keepAlive.toMillis(), TimeUnit.MILLISECONDS);
return requestConfigBuilder.setRedirectsEnabled(false).build();
}
private static Timeout getTimeoutMillis(Duration timeout, String name) {
if (timeout == null) {
switch (name) {
case "idle":
return Timeout.ofMilliseconds(DEFAULT_MAX_IDLE_TIMEOUT);
case "connect":
return Timeout.ofMilliseconds(DEFAULT_MAX_CONN_TIMEOUT);
case "response":
return Timeout.ofMilliseconds(DEFAULT_MAX_RESPONSE_TIMEOUT);
case "connectionRequest":
return Timeout.ofMilliseconds(DEFAULT_CONNECT_REQUEST_TIMEOUT);
default:
return Timeout.ofMilliseconds(DEFAULT_TIMEOUT);
}
}
if (timeout.isZero() || timeout.isNegative()) {
return Timeout.ofMilliseconds(0);
}
return Timeout.ofMilliseconds(Math.max(timeout.toMillis(), DEFAULT_MINIMUM_TIMEOUT));
}
private static int getMaxConnTotal(int maxConnTotal) {
if (maxConnTotal <= 0) {
return Runtime.getRuntime().availableProcessors() * 10;
}
return maxConnTotal;
}
private ConnectionKeepAliveStrategy buildKeepAliveStrategy() {
long maxIdle = getTimeoutMillis(this.maxIdleTimeOut, "idle").toMilliseconds();
return maxIdle > 0 ? new SdkConnectionKeepAliveStrategy(maxIdle) : null;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy