I am using following version of httpclient api to call the rest webservice.
httpcore4.4.9
httpclient 4.5.9
I am using the ExecutorService to execute the task where it is calling my following methods to get the data from rest API. ExecutorService execute about 30+ rest call in one transaction and i observed that, httpclient HUNG or SLOW for few of the rest call and it hit the performance issue. Can you please check if below i am using httpclient correct way ?
String output = null;
CloseableHttpClient httpClient = getHttpClients();
try (CloseableHttpResponse response = httpClient.execute(httpGet)) {
HttpEntity entity = response.getEntity();
output = EntityUtils.toString(entity);
EntityUtils.consume(response.getEntity());
} catch (Exception e) {
log.error("error during call to REST API " + httpGet.getURI() + " ", e);
} finally {
httpClient.close();
httpGet.releaseConnection();
httpGet.abort();
}
return output;
}
private CloseableHttpClient getHttpClients() {
long startTime = System.currentTimeMillis();
long endTime = 0;
int timeout = 12000;
RequestConfig.Builder requestBuilder = RequestConfig.custom();
requestBuilder.setConnectTimeout(timeout);
requestBuilder.setConnectionRequestTimeout(timeout);
SocketConfig socketConfig = SocketConfig.custom().setSoTimeout(timeout).build();
HttpClientBuilder builder = HttpClientBuilder.create();
builder.setDefaultRequestConfig(requestBuilder.build());
builder.disableContentCompression();
builder.setDefaultSocketConfig(socketConfig);
CloseableHttpClient httpClient = builder
.build();
endTime = System.currentTimeMillis();
log.debug("Total time took to build client = " + (endTime - startTime));
return httpClient;
} ```
As per my experience, this problem is occurring because of EntityUtils.consume(response.getEntity()) .
You could find what it actually does here.
Try removing and running your code to match the speed and decide if you want it or not.
Below is the code used by me:
CloseableHttpClient httpClient = HttpClients.createDefault();
try {
HttpGet request = new HttpGet(url);
CloseableHttpResponse response = httpClient.execute(request);
String responseString = EntityUtils.toString(response.getEntity());
} catch (Exception ex) {
log.error(ex.toString());
}
Try to adjust MaxTotal and MaxPerRoute variable in PoolingHttpClientConnectionManager class.
connectionManager.setMaxTotal(maxTotalConnections);
connectionManager.setDefaultMaxPerRoute(maxConnectionsPerRoute);
Related
Could you please help me with the following:
I have the following method:
public static CloseableHttpResponse getRequest (String url) {
try (CloseableHttpClient httpClient = HttpClients.createDefault();){
HttpGet httpget = new HttpGet(url); //http get request (create get connection with particular url)
return httpClient.execute(httpget);
} catch (Exception e) {
throw new RuntimeException(e.getMessage(), e);
}
}
Where I use CloseableHttpClient with try-with-resources
I invoke method in some simple test:
CloseableHttpResponse closeableHttpResponse = RestClient.getRequest("https://reqres.in/api/users?page=2");
String responseString = EntityUtils.toString(closeableHttpResponse.getEntity(), "UTF-8");
JSONObject responseJson = new JSONObject(responseString);
System.out.println(responseJson);
And I am getting error: org.apache.http.TruncatedChunkException: Truncated chunk (expected size: 379; actual size: 358)
When I am not using try-with-resources like that:
public static CloseableHttpResponse getRequest (String url) throws IOException {
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpGet httpget = new HttpGet(url); //http get request (create get connection with particular url)
return httpClient.execute(httpget);
}
I have no error at all! Could you please explain - what the wrong? I am newbie and have no clue - some examples from internet are working good...
The try-with-resources block will automatically call close() on the object, so the return from one of those getRequest calls is a closed CloseableHttpClient instance.
The call without try-with-resources will return a working (not closed) CloseableHttpClient.
In my Xpages application I am calling an external service to collect data.
Users are complaining that they sometimes get a timeout error message:
Connect to customerbank.acme.se:20543 [customerbank.acme.se/127.17.27.172] failed: Connection timed out: connect
I assumed the timeout would result in an IOException but apparently not. How can I catch this error?
Below is part of my code. The logic of handling the response I have left out.
private CloseableHttpClient httpclient;
try{
HttpClientBuilder cb = HttpClientBuilder.create();
RequestConfig requestConfig = RequestConfig.custom()
.setSocketTimeout(30 * 1000)
.setConnectTimeout(30 * 1000)
.setConnectionRequestTimeout(30 * 1000)
.build();
cb.setDefaultRequestConfig(requestConfig);
httpclient = cb.build();
HttpPost httpPost = new HttpPost(urlFromConfiguration);
httpPost.setHeader("Content-Type", "application/json");
HttpEntity entity;
entity = new ByteArrayEntity(JSONobj.toString().getBytes("UTF-8"));
httpPost.setEntity(entity);
CloseableHttpResponse response = httpclient.execute(httpPost);
if (200 == response.getStatusLine().getStatusCode()){//response received
//perform some logic with the response...
}
} catch (IOException e) {
OpenLogUtil.logError(e);
FacesContext.getCurrentInstance().addMessage(null, new javax.faces.application.FacesMessage(javax.faces.application.FacesMessage.SEVERITY_ERROR, "some IO exception occurred", ""));
} catch (Exception e) {
OpenLogUtil.logError(e);
FacesContext.getCurrentInstance().addMessage(null, new javax.faces.application.FacesMessage(javax.faces.application.FacesMessage.SEVERITY_ERROR, "some general error has occured" , ""));
}
I think this Baeldung page can help you:
"Note that the connection timeout will result in an
org.apache.http.conn.ConnectTimeoutException being thrown, while
socket timeout will result in a java.net.SocketTimeoutException."
Apache Http client that you are using is a great utility. But it could be a bit heavy and cumbersome for a relatively simple task that you are running. There is a much simpler Http client provided in MgntUtils Open source library (written by me). It may be not as comprehensive as Apache one, but is much simpler in use. It does throw IOException upon connection or time-out error. In your case it could be an alternative to use. Take a look at Javadoc. Library itself provided as Maven artifacts and on Git (including source code and Javadoc). All in all your code may look like this:
private static void testHttpClient() {
HttpClient client = new HttpClient();
client.setContentType("application/json");
String content = null;
try {
content = client.sendHttpRequest("http://yourUrl.com", HttpMethod.POST, JSONobj.toString());
//content holds the response. Do your logic here
} catch (IOException e) {
//Error Handling is here
content = TextUtils.getStacktrace(e, false);
}
}
I'm send a request to YouTrack api to create issue.
String url = yBaseUrl + "/rest/issue?Task&"+ URLEncoder.encode(subject)+"&"+URLEncoder.encode(desc);
HttpClient client = new DefaultHttpClient();
HttpPut request = new HttpPut(url);
// add request header
((DefaultHttpClient) client).setCookieStore(cookie);
HttpResponse response = null;
//client.execute(post);
try {
response = client.execute(request);
System.out.println(response.getStatusLine().getStatusCode());
} catch (IOException e) {
e.printStackTrace();
}
result - 403 code.
Why setCookieStore not working?
The problem was incorrect api url. Need use /rest/issue?project=Task&summary="+ URLEncoder.encode(subject)... The question is closed
I use lot of http connection with Apache HttpClient (org.apache.httpcomponents 4.3.6) to test servers and I cannot force connections to close, even when I schedule HttpConnectionManager to httpClient.getConnectionManager().shutdown(); after 10 seconds in another thread.
httpClient.close() also doesn't help.
Connections can last for minutes or even hours.
I have tried custom SocketConfig and this also not helps:
SocketConfig socketConfig = SocketConfig.custom()
.setSoKeepAlive(false)
.setSoLinger(5)
.setSoReuseAddress(true)
.setSoTimeout(5000)
.setTcpNoDelay(true).build();
The way I am fetching the content:
HttpUriRequest request = new HttpGet(url);
HttpResponse response = httpClient.execute(request);
try (InputStream in = response.getEntity().getContent()) {
String result = IOUtils.toString(in, StandardCharsets.UTF_8);
httpClient.close();
return result;
}
The way I am building HTTP Client:
SocketConfig socketConfig = SocketConfig.custom()
.setSoKeepAlive(false)
.setSoLinger(configuration.getInt("proxy.list.socket.so.linger"))
.setSoReuseAddress(true)
.setSoTimeout(configuration.getInt("proxy.list.socket.so.timeout"))
.setTcpNoDelay(true).build();
HttpClientBuilder builder = HttpClientBuilder.create();
builder.disableAutomaticRetries();
builder.disableContentCompression();
builder.disableCookieManagement();
builder.disableRedirectHandling();
builder.setConnectionReuseStrategy(new NoConnectionReuseStrategy());
builder.setDefaultSocketConfig(socketConfig);
One of my prototypes of doing shutdown:
shutdownExecutor.schedule(() -> {
httpClient.getConnectionManager().closeExpiredConnections();
httpClient.getConnectionManager().closeIdleConnections(1, TimeUnit.SECONDS);
httpClient.getConnectionManager().shutdown();
httpClient.notifyAll();
try {
httpClient.close();
} catch (IOException ex) {
}
}, configuration.getInt("proxy.test.forced.timeout.seconds"), TimeUnit.SECONDS);
String content = HttpContentFetcher.getAndCloseClient(url, httpClient);
RequestConfig has helped. Now it looks like all the connections are discarded in specified limits.
RequestConfig config= RequestConfig.custom()
.setCircularRedirectsAllowed(false)
.setConnectionRequestTimeout(4000)
.setConnectTimeout(4000)
.setMaxRedirects(0)
.setRedirectsEnabled(false)
.setSocketTimeout(4000)
.setStaleConnectionCheckEnabled(true).build();
request.setConfig(config);
In a Java, I want to send HttpPost every 5 secs without waiting for the response. How can I do that?
I use the following code:
HttpClient httpClient = new DefaultHttpClient();
HttpPost post = new HttpPost(url);
StringEntity params = new StringEntity(json.toString() + "\n");
post.addHeader("content-type", "application/json");
post.setEntity(params);
httpClient.execute(post);
Thread.sleep(5000);
httpClient.execute(post);
but it does not work.
Even though I lose the previous connection and set up a new connection to send the second, the second execute function is always blocked.
Your question leaves a bunch of questions, but the basic point of it can be achieved by:
while(true){ //process executes infinitely. Replace with your own condition
Thread.sleep(5000); // wait five seconds
httpClient.execute(post); //execute your request
}
I tried your code and I got the exception :
java.lang.IllegalStateException: Invalid use of BasicClientConnManager: connection still allocated.
Make sure to release the connection before allocating another one.
This exception is already logged in HttpClient 4.0.1 - how to release connection?
I was able to release the connection by consuming the response with the following code:
public void sendMultipleRequests() throws ClientProtocolException, IOException, InterruptedException {
HttpClient httpClient = new DefaultHttpClient();
HttpPost post = new HttpPost("http://www.google.com");
HttpResponse response = httpClient.execute(post);
HttpEntity entity = response.getEntity();
EntityUtils.consume(entity);
Thread.sleep(5000);
response = httpClient.execute(post);
entity = response.getEntity();
EntityUtils.consume(entity);
}
Using DefaultHttpClient is synchronous which means that program is blocked waiting for the response. Instead of that you could use async-http-client library to perform asynchronous requests (you can download jar files from search.maven.org if you're not familiar with Maven). Sample code may look like:
import com.ning.http.client.*; //imports
try {
AsyncHttpClient asyncHttpClient = new AsyncHttpClient();
while(true) {
asyncHttpClient
.preparePost("http://your.url/")
.addParameter("postVariableName", "postVariableValue")
.execute(); // just execute request and ignore response
System.out.println("Request sent");
Thread.sleep(5000);
}
} catch (Exception e) {
System.out.println("oops..." + e);
}