I am trying to hit a server using HTTP client using PoolingClientConnectionManager setting max connections for individual hosts
//Code that initializes my connection manager and HTTP client
HttpParams httpParam = httpclient.getParams();
HttpConnectionParams.setSoTimeout(httpParam, SOCKET_TIMEOUT);
HttpConnectionParams.setConnectionTimeout(httpParam, CONN_TIMEOUT);
httpclient.setParams(httpParam);
//Run a thread which closes Expired connections
new ConnectionManager(connManager).start();
//Code that executes my request
HttpPost httpPost = new HttpPost(url);
HttpEntity httpEntity = new StringEntity(request, "UTF-8");
httpPost.setEntity(httpEntity);
Header acceptEncoding = new BasicHeader("Accept-Encoding", "gzip,deflate");
httpPost.setHeader(acceptEncoding);
if(contenttype != null && !contenttype.equals("")){
Header contentType = new BasicHeader("Content-Type", contenttype);
httpPost.setHeader(contentType);
}
InputStream inputStream = null;
LOG.info(dataSource + URL + url + REQUEST + request);
HttpResponse response = httpclient.execute(httpPost);
That is we are using Connection pooling for http persistence .
We are getting this error sporadically :
The target server failed to respond
org.apache.http.NoHttpResponseException: The target server failed to respond
at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:95)
at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:62)
at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:254)
at org.apache.http.impl.AbstractHttpClientConnection.receiveResponseHeader(AbstractHttpClientConnection.java:289)
at org.apache.http.impl.conn.DefaultClientConnection.receiveResponseHeader(DefaultClientConnection.java:252)
at org.apache.http.impl.conn.ManagedClientConnectionImpl.receiveResponseHeader(ManagedClientConnectionImpl.java:191)
at org.apache.http.protocol.HttpRequestExecutor.doReceiveResponse(HttpRequestExecutor.java:300)
at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:127)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:517)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:906)
Does any one know how to resolve this?
We are shutting down idle connections as well.
Can some Please help.
http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html
Probably, it is a bug in the HttpClient.
If you are using the HttpClient 4.4, please try to upgrade to 4.4.1.
If you want for more information, please look at this link.
If you can't upgrade, the following links might be helpful.
http://www.nuxeo.com/blog/using-httpclient-properly-avoid-closewait-tcp-connections/
Good luck!
Recently faced similar while using HttpClient 5.
On enabling the HttpClient logs and found that the issue was due to stale connections.
Adding the below helped to solve the issue, it detects and validates the connections that have become stale while kept inactive in the pool before reuse.
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
connectionManager.setValidateAfterInactivity(timeinmilliseconds);
Related
In my test application I execute consecutive HttpGet requests to the same host with Apache HttpClient but upon each next request it turns out that the previous HttpConnection is closed and the new HttpConnection is created.
I use the same instance of HttpClient and don't close responses. From each entity I get InputStream, read from it with Scanner and then close the Scanner. I have tested KeepAliveStrategy, it returns true. The time between requests doesn't exceed keepAlive or connectionTimeToLive durations.
Can anyone tell me what could be the reason for such behavior?
Updated
I have found the solution. In order to keep the HttpConnecton alive it is necessary to set HttpClientConnectionManager when building HttpClient. I have used BasicHttpClientConnectionManager.
ConnectionKeepAliveStrategy keepAliveStrat = new DefaultConnectionKeepAliveStrategy() {
#Override
public long getKeepAliveDuration(HttpResponse response, HttpContext context)
{
long keepAlive = super.getKeepAliveDuration(response, context);
if (keepAlive == -1)
keepAlive = 120000;
return keepAlive;
}
};
HttpClientConnectionManager connectionManager = new BasicHttpClientConnectionManager();
try (CloseableHttpClient httpClient = HttpClients.custom()
.setConnectionManager(connectionManager) // without this setting connection is not kept alive
.setDefaultCookieStore(store)
.setKeepAliveStrategy(keepAliveStrat)
.setConnectionTimeToLive(120, TimeUnit.SECONDS)
.setUserAgent(USER_AGENT)
.build())
{
HttpClientContext context = new HttpClientContext();
RequestConfig config = RequestConfig.custom()
.setCookieSpec(CookieSpecs.DEFAULT)
.setSocketTimeout(10000)
.setConnectTimeout(10000)
.build();
context.setRequestConfig(config);
HttpGet httpGet = new HttpGet(uri);
CloseableHttpResponse response = httpClient.execute(httpGet, context);
HttpConnection conn = context.getConnection();
HttpEntity entity = response.getEntity();
try (Scanner in = new Scanner(entity.getContent(), ENC))
{
// do something
}
System.out.println("open=" + conn.isOpen()); // now open=true
HttpGet httpGet2 = new HttpGet(uri2); // on the same host with other path
// and so on
}
Updated 2
In general checking connections with conn.isOpen() is not proper way to check the connections state because: "Internally HTTP connection managers work with instances of ManagedHttpClientConnection acting as a proxy for a real connection that manages connection state and controls execution of I/O operations. If a managed connection is released or get explicitly closed by its consumer the underlying connection gets detached from its proxy and is returned back to the manager. Even though the service consumer still holds a reference to the proxy instance, it is no longer able to execute any I/O operations or change the state of the real connection either intentionally or unintentionally." (HttpClent Tutorial)
As have pointed #oleg the proper way to trace connections is using the logger.
First of all you need to make sure remote server you're working with does support keep-alive connections. Just simply check whether remote server does return header Connection: Keep-Alive or Connection: Closed in each and every response. For Close case there is nothing you can do with that. You can use this online tool to perform such check.
Next, you need to implement the ConnectionKeepAliveStrategy as defined in paragraph #2.6 of this manual. Note that you can use existent DefaultConnectionKeepAliveStrategy since HttpClient version 4.0, so that your HttpClient will be constructed as following:
HttpClient client = HttpClients.custom()
.setKeepAliveStrategy(DefaultConnectionKeepAliveStrategy.INSTANCE)
.build();
That will ensure you HttpClient instance will reuse the same connection via keep-alive mechanism if it is being supported by server.
Your application must be closing response objects in order to ensure proper resource de-allocation of the underlying connections. Upon response closure HttpClient keeps valid connections alive and returns them back to the connection manager (connection pool).
I suspect your code simply leaks connections and every request ens up with a newly created connection while all previous connections keep on piling up in memory.
From the example at HttpClient website:
// In order to ensure correct deallocation of system resources
// the user MUST call CloseableHttpResponse#close() from a finally clause.
// Please note that if response content is not fully consumed the underlying
// connection cannot be safely re-used and will be shut down and discarded
// by the connection manager.
So as #oleg said you need to close the HttpResponse before checking the connection status.
I recently switched from java.net to org.apache.http.client, I have setup a ClosableHttpClient with the HttpClientBuilder. As connection manager I am using the BasicHttpClientConnectionManager.
Now I have the problem that very often when I create some HTTP request I get a timeout exception. It seems that the connection manager is keeping connections open to reuse them but if the system is idle for a few minutes then this connection will timeout and when I make the next request the first thing I get is a timeout. Repeating the same request one more time then usually works without any problem.
Is there a way to configure the BasicHttpClientConnectionManager in order to not reuse its connections and create a new connection each time?
There several ways of dealing with the problem
Evict idle connections once no longer needed. The code below effectively disables connection persistence by closing out persistent connections after each HTTP exchange.
BasicHttpClientConnectionManager cm = new BasicHttpClientConnectionManager();
CloseableHttpClient httpclient = HttpClients.custom().setConnectionManager(cm).build();
...
try (CloseableHttpResponse response = httpclient.execute(new HttpGet("/"))) {
System.out.println(response.getStatusLine());
EntityUtils.consume(response.getEntity());
}
cm.closeIdleConnections(0, TimeUnit.MILLISECONDS);
Limit connection keep-alive time to something relatively small-ish
BasicHttpClientConnectionManager cm = new BasicHttpClientConnectionManager();
CloseableHttpClient httpclient = HttpClients.custom()
.setConnectionManager(cm)
.setKeepAliveStrategy((response, context) -> 1000)
.build();
try (CloseableHttpResponse response = httpclient.execute(new HttpGet("/"))) {
System.out.println(response.getStatusLine());
EntityUtils.consume(response.getEntity());
}
(Recommended) Use pooling connection manager and set connection total time to live to a finite value. There are no benefits to using the basic connection manager compared to the pooling one unless your code is expected to run in an EJB container.
CloseableHttpClient httpclient = HttpClients.custom()
.setConnectionTimeToLive(5, TimeUnit.SECONDS)
.build();
try (CloseableHttpResponse response = httpclient.execute(new HttpGet("/"))) {
System.out.println(response.getStatusLine());
EntityUtils.consume(response.getEntity());
}
I have a REST webservice with some methods.
I'm sending requests to the rest with Apache HttpClient 4.
When I make a connection to this rest, in a method that is bigger and slower, it throws a NoHttpResponseException.
After googling, I discovered that the server is cutting down the connection with my client app.
So, I tried to disable the timeout this way :
DefaultHttpClient httpclient = null;
HttpParams params = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(params, 0);
HttpConnectionParams.setSoTimeout(params, 0);
HttpConnectionParams.setStaleCheckingEnabled(params, true);
httpclient = new DefaultHttpClient(params);
httpclient.execute(httpRequest, httpContext);
But it failed. The request dies in 15 seconds (possible default timeout?)
Does anyone know the best way to do this?
I would suggest that you return data to the client before the timeout can occur. This may just be some bytes that says "working" to the client. By trickling the data out, you should be able to keep the client alive.
I have a http client which is based on the apache http client and it seems to have no problem with ssl certificates. I have a unit test for both globally recognized certs and self signed certs with a custom SSLSocketFactory.
However when I ran the same code behind a proxy, it stopped working. I keep getting this dreaded exception:
javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
at com.sun.net.ssl.internal.ssl.SSLSessionImpl.getPeerCertificates(SSLSessionImpl.java:352)
at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:128)
at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:572)
at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:180)
at org.apache.http.impl.conn.ManagedClientConnectionImpl.open(ManagedClientConnectionImpl.java:294)
at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:640)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:479)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:906)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:805)
I reduced the code to the bare minimum and it still throws the same exception. The code:
URI uri = new URI("https://www.google.com");
DefaultHttpClient client = new DefaultHttpClient();
client.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY,
new HttpHost("proxy.int", 8080, "https"));
HttpUriRequest request = new HttpGet(uri);
HttpResponse response = client.execute(request);
I wasn't sure if it uses the default ssl settings if nothing is specified so I added it explicitly as well:
URI uri = new URI("https://www.google.com");
DefaultHttpClient client = new DefaultHttpClient();
client.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY,
new HttpHost("proxy.int", 8080, "https"));
client.getConnectionManager().getSchemeRegistry().register(
new Scheme("https", 443, SSLSocketFactory.getSystemSocketFactory()));
HttpUriRequest request = new HttpGet(uri);
HttpResponse response = client.execute(request);
I also tried the getSocketFactory() (not entirely sure what the difference is with getSystemSocketFactory()), still the same error though.
EDIT:
The proxy has optional authentication and I have tried both with and without. The authentication information was set using the following code:
client.getCredentialsProvider().setCredentials(
new AuthScope("proxy.int", 8080),
new UsernamePasswordCredentials("user", "password")
);
Exactly the same error.
The problem was in the proxy declaration, I had to specify "http" instead of "https":
client.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY,
new HttpHost("proxy.int", 8080, "http"));
Is there any class for reading http pages that return a java.io.InputStream and its timeout be reliable?
I tried java.net.URLConnection and it doesn't have a reliable timeout (it takes more time that it set to timeout reach)? My Code is here:
URLConnection con = url.openConnection();
con.setConnectTimeout(2000);
con.setReadTimeout(2000);
InputStream in = con.getInputStream();
I expect that the reason that the timeout is not working for you is that you are setting the timeout after the connection has been established, or you are using the wrong setter. It is also possible that you are using "non-standard" version of URLConnection ...
"Some non-standard implementation of this method ignores the specified timeout. To see the read timeout set, please call getReadTimeout()." (or getConnectTimeout())
If you posted the relevant part of your actual code we could give you a better answer ...
Alternatively, use the Apache HttpClient library.
You can use Apache HttpClient to read http pages, it also has an http parser.check this for further reference about httpclient. you can get an InputStream object using their API like this.
HttpClient httpclient = new DefaultHttpClient();
// Prepare a request object
HttpGet httpget = new HttpGet("http://www.apache.org/");
// Execute the request
HttpResponse response = httpclient.execute(httpget);
// Examine the response status
System.out.println(response.getStatusLine());
// Get hold of the response entity
HttpEntity entity = response.getEntity();
// If the response does not enclose an entity, there is no need
// to worry about connection release
if (entity != null) {
InputStream instream = entity.getContent();
and coming to timeout part, it totally depends on the network and you cant do much about it from your java code.