I am using Apache HttpClient 4.5 for my soap webservice.
Currently, I have encountered an issue where the keep alive in httpclient is ignored when TLSv1.2 is used. However, the keep alive is working if using HTTP.
Do you guys have some idea on it?
My code is shown as below:
Main Class: HttpClientPool.java
public class HttpClientPool {
private static PoolingHttpClientConnectionManager manager = null;
private static CloseableHttpClient httpClient = null;
private static final Logger logger = Logger.getLogger(HttpClientPool.class);
public static synchronized CloseableHttpClient getHttpClient(){
if(httpClient==null){
//Some function to get SSLConnectionSocketFactory in Singleton
SSLConnectionSocketFactory sslConnSocFac = getSSLConnectionSocketFactory();
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("https", sslConnSocFac)
.build();
HttpConnectionFactory<HttpRoute, ManagedHttpClientConnection> connectionFactory = new ManagedHttpClientConnectionFactory(
DefaultHttpRequestWriterFactory.INSTANCE, DefaultHttpResponseParserFactory.INSTANCE);
DnsResolver dnsResolver = SystemDefaultDnsResolver.INSTANCE;
manager = new PoolingHttpClientConnectionManager(socketFactoryRegistry, connectionFactory, dnsResolver);
SocketConfig deaultSocketConfig = SocketConfig.custom().setTcpNoDelay(true).build();
manager.setDefaultSocketConfig(deaultSocketConfig);
manager.setMaxTotal(300);
manager.setDefaultMaxPerRoute(200);
manager.setValidateAfterInactivity(50*1000);
RequestConfig defaultRequestConfig = RequestConfig.custom()
.setConnectTimeout(20*1000)
.setSocketTimeout(50*1000)
.setConnectionRequestTimeout(20000)
.build();
ConnectionKeepAliveStrategy myStrategy = new ConnectionKeepAliveStrategy() {
public long getKeepAliveDuration(HttpResponse httpResponse, org.apache.http.protocol.HttpContext context) {
return 1000 * 1000;
}
};
httpClient = HttpClients.custom()
.setConnectionManager(manager)
.setConnectionManagerShared(false)
.evictIdleConnections(60l, TimeUnit.SECONDS)
.evictExpiredConnections()
.setConnectionTimeToLive(60, TimeUnit.SECONDS)
.setDefaultRequestConfig(defaultRequestConfig)
.setConnectionReuseStrategy(DefaultConnectionReuseStrategy.INSTANCE)
.setKeepAliveStrategy(myStrategy)
.setRetryHandler(new DefaultHttpRequestRetryHandler(0, false))
.build();
Runtime.getRuntime().addShutdownHook(new Thread(){
@Override
public void run(){
try {
httpClient1.close();
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
return httpClient;
}
private static SSLConnectionSocketFactory getSSLConnectionSocketFactory() {
//some working
return sslConnectionSocketFactory;
}
}
Trigger Class: webServiceClient.java
public class webServiceClient{
HttpClientPool httpClientPool;
private static final Logger logger = Logger.getLogger(HttpClientPool.class);
public sendSOAPMessage(String url, String soapAction){
HttpPost post = new HttpPost(url);
HttpEntity entity = new ByteArrayEntity(xml.getBytes("UTF-8"));
post.setEntity(entity);
post.setHeader("Content-type", "application/soap+xml; charset=UTF-8");
post.setHeader("SOAPAction", soapAction);
post.setHeader("Connection", "Keep-Alive");
post.setHeader("Keep-Alive", "header");
CloseableHttpResponse response = httpClientPool.getHttpClient().execute(post);
String result = EntityUtils.toString(response.getEntity());
logger.info("Response: " + result);
EntityUtils.consume(response.getEntity());
response.close();
}
}
You have two options here:
Pass user token (which in your case should be the CN of the user certificate) to the #sendSOAPMessage
as a parameter.
public class webServiceClient{
HttpClientPool httpClientPool;
private static final Logger logger = Logger.getLogger(HttpClientPool.class);
public sendSOAPMessage(String url, String soapAction, String userToken){
HttpPost post = new HttpPost(url);
HttpEntity entity = new ByteArrayEntity(xml.getBytes("UTF-8"));
post.setEntity(entity);
post.setHeader("Content-type", "application/soap+xml; charset=UTF-8");
post.setHeader("SOAPAction", soapAction);
post.setHeader("Connection", "Keep-Alive");
post.setHeader("Keep-Alive", "header");
HttpClientContext clientContext = HttpClientContext.create();
clientContext.setUserToken(userToken);
try (CloseableHttpResponse response = httpClientPool.getHttpClient().execute(post, clientContext)) {
String result = EntityUtils.toString(response.getEntity());
logger.info("Response: " + result);
EntityUtils.consume(response.getEntity());
}
}
}
If you are certain your application does not have to support multiple user identities disable connection state tracking.
httpClient = HttpClients.custom()
.disableConnectionState()
.build();