package core.framework.api.http; import core.framework.api.util.StopWatch; import org.apache.http.client.config.RequestConfig; import org.apache.http.config.SocketConfig; import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.conn.ssl.TrustSelfSignedStrategy; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.client.HttpClients; import org.apache.http.ssl.SSLContextBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.security.KeyManagementException; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.time.Duration; /** * @author neo */ public final class HTTPClientBuilder { private final Logger logger = LoggerFactory.getLogger(HTTPClientBuilder.class); private Duration timeout = Duration.ofSeconds(60); private int maxConnections = 100; private Duration keepAliveTimeout = Duration.ofSeconds(60); private Duration slowOperationThreshold = Duration.ofSeconds(30); private boolean enableCookie = false; private boolean enableRedirect = false; private String userAgent = "HTTPClient"; public HTTPClient build() { StopWatch watch = new StopWatch(); try { HttpClientBuilder builder = HttpClients.custom(); builder.setUserAgent(userAgent); builder.setKeepAliveStrategy((response, context) -> keepAliveTimeout.toMillis()); builder.setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE) .setSSLContext(new SSLContextBuilder().loadTrustMaterial(TrustSelfSignedStrategy.INSTANCE).build()); // builder use PoolingHttpClientConnectionManager by default, and connTimeToLive will be set by keepAlive value builder.setDefaultSocketConfig(SocketConfig.custom().setSoKeepAlive(true).build()); builder.setDefaultRequestConfig(RequestConfig.custom() .setSocketTimeout((int) timeout.toMillis()) .setConnectionRequestTimeout((int) timeout.toMillis()) .setConnectTimeout((int) timeout.toMillis()).build()); builder.setMaxConnPerRoute(maxConnections) .setMaxConnTotal(maxConnections); builder.disableAuthCaching(); builder.disableConnectionState(); builder.disableAutomaticRetries(); // retry should be handled in framework level with better trace log if (!enableRedirect) builder.disableRedirectHandling(); if (!enableCookie) builder.disableCookieManagement(); CloseableHttpClient httpClient = builder.build(); return new HTTPClient(httpClient, userAgent, slowOperationThreshold); } catch (NoSuchAlgorithmException | KeyManagementException | KeyStoreException e) { throw new Error(e); } finally { logger.info("create http client, elapsedTime={}", watch.elapsedTime()); } } public HTTPClientBuilder maxConnections(int maxConnections) { this.maxConnections = maxConnections; return this; } public HTTPClientBuilder timeout(Duration timeout) { this.timeout = timeout; return this; } public HTTPClientBuilder keepAliveTimeout(Duration keepAliveTimeout) { this.keepAliveTimeout = keepAliveTimeout; return this; } public HTTPClientBuilder slowOperationThreshold(Duration slowOperationThreshold) { this.slowOperationThreshold = slowOperationThreshold; return this; } public HTTPClientBuilder userAgent(String userAgent) { this.userAgent = userAgent; return this; } public HTTPClientBuilder enableCookie() { enableCookie = true; return this; } public HTTPClientBuilder enableRedirect() { enableRedirect = true; return this; } }