Hi team: I have a question regarding the use of Apache HttpClient 5 CloseableHttpClient in a Spring Boot 3 application. I am executing the following code:
try
{
final HttpGet httpGet = new HttpGet("http://httpbin.org/get");
httpGet.addHeader("content-type", "application/json");
HttpClientResponseHandler<String> responseHandler = new HttpClientResponseHandler<String>()
{
@Override
public String handleResponse(ClassicHttpResponse _httpResponse) throws HttpException, IOException
{
int status = _httpResponse.getCode();
if (status >= 200 && status < 300)
{
HttpEntity entity = _httpResponse.getEntity();
String stringEntity = EntityUtils.toString(entity);
return entity != null ? stringEntity : null;
}
else
{
throw new ClientProtocolException("Unexpected response status: " + status);
}
}
};
responseBody = closeableHttpClient.execute(httpGet, responseHandler);
log.info("Response Body: " + responseBody);
}
catch (NoSuchElementException _e)
{
log.error("NoSuchElementException: "+ _e.getMessage());
_e.printStackTrace();
}
catch (ClientProtocolException _e)
{
log.error("ClientProtocolException: "+ _e.getMessage());
}
catch (IOException _e)
{
log.error("IOException: "+ _e.getMessage());
}
catch (Exception _e)
{
log.error("Exception: "+ _e.getMessage());
}
But when I execute this code, I get the following exception:
NoSuchElementException: No more header elements available java.util.NoSuchElementException: No more header elements available
To get the CloseableHttpClient, I have the following configurations:
@Slf4j
@Configuration
@EnableScheduling
public class HttpConfig
@Bean
@ConditionalOnMissingBean
public CloseableHttpClient httpClient(HttpClientConnectionManager connectionManager)
{
RequestConfig requestConfig = RequestConfig.custom()
.setConnectionRequestTimeout(Timeout.ofMilliseconds(15000))
.setResponseTimeout(Timeout.ofMilliseconds(15000))
.build();
return HttpClients.custom()
.setConnectionManager(connectionManager)
.setKeepAliveStrategy(getConnectionKeepAliveStrategy())
.setDefaultRequestConfig(requestConfig)
.build();
}
@Bean(destroyMethod = "")
@ConditionalOnMissingBean
public HttpClientConnectionManager httpClientConnectionManager()
{
HttpHost host1 = new HttpHost("httpbin.org/get", 80);
final PoolingHttpClientConnectionManager connectionManager = PoolingHttpClientConnectionManagerBuilder.create()
.setConnectionFactory(getHttpConnectionFactory())
.setPoolConcurrencyPolicy(PoolConcurrencyPolicy.STRICT)
.setConnPoolPolicy(PoolReusePolicy.LIFO)
.build();
connectionManager.setMaxTotal(100);
connectionManager.setDefaultMaxPerRoute(20);
connectionManager.setMaxPerRoute(new HttpRoute(host1), 10);
return connectionManager;
}
public ConnectionKeepAliveStrategy getConnectionKeepAliveStrategy()
{
final ConnectionKeepAliveStrategy connectionKeepAliveStrategy = new ConnectionKeepAliveStrategy()
{
@Override
public TimeValue getKeepAliveDuration(HttpResponse response, HttpContext context)
{
Args.notNull(response, "HTTP response");
final Iterator<HeaderElement> iterator = MessageSupport.iterate(response, HeaderElements.KEEP_ALIVE);
final HeaderElement headerElement = iterator.next();
final String param = headerElement.getName();
final String value = headerElement.getValue();
if (value != null && param.equalsIgnoreCase("timeout"))
{
try
{
return TimeValue.ofSeconds(Long.parseLong(value));
}
catch (final NumberFormatException e)
{
log.error("Connection Keep-Alive Strategy: Number Format Exception: Safely Ignore: " + e.getMessage());
}
}
return TimeValue.ofSeconds(5);
}
};
return connectionKeepAliveStrategy;
}
@Bean
public Runnable getIdleConnectionMonitor(final PoolingHttpClientConnectionManager connectionManager)
{
return new Runnable()
{
@Override
@Scheduled(fixedDelay = 15000)
public void run()
{
try
{
if (connectionManager != null)
{
connectionManager.closeExpired();
connectionManager.closeIdle(Timeout.ofSeconds(60000));
}
}
catch (Exception e)
{
log.error("IdleConnectionMonitor - Exception occurred: Message = {}, Exception = {}", e.getMessage(), e);
}
}
};
}
I have no idea what could be wrong here. Any help would be much appreciated.