I'm using Apache Httpclient for Ajax-calls on a website. In some cases requests to external webservice fail, often with:
I/O exception (java.net.ConnectException) caught when processing request: Connection timed out: connect.
In that case, more often than not, I want to skip retrying the request (something that Httpclient seems to do automatically) .
However, I can't find any method, param, etc. to skip retrying.
anyone?
Thanks Geert-Jan
From httpclient 4.3 use HttpClientBuilder
HttpClientBuilder.create().disableAutomaticRetries().build();
client.setHttpRequestRetryHandler(new DefaultHttpRequestRetryHandler(0, false));
That would do it.
OK. There is issue in the Documentation. Also there has been change in API and methods.
So if you want to use DefaultHttpRequestRetryHandler , here are the ways to do that,
DefaultHttpClient httpClient = new DefaultHttpClient();
DefaultHttpRequestRetryHandler retryHandler = new DefaultHttpRequestRetryHandler(0, false);
httpClient.setHttpRequestRetryHandler(retryHandler);
or
HttpClient httpClient = new DefaultHttpClient();
DefaultHttpRequestRetryHandler retryHandler = new DefaultHttpRequestRetryHandler(0, false);
((AbstractHttpClient)httpClient).setHttpRequestRetryHandler(retryHandler);
In first one, we use concrete DefaultHttpClient (which is a subclass of AbstractHttpClient and so has the setHttpRequestRetryHandler() method.)
In second one, we are programming to the HttpClient interface (which sadly doesn't expose that method, and this is weird !! ehh), so we have to do that nasty cast.
There's a description in the HttpClient tutorial.
client.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
new DefaultHttpMethodRetryHandler());
See the tutorial for more information, for instance this may be harmful if the request has side effects (i.e. is not idempotent).
The cast to AbstractHttpClient is not necessary. Another way is to use a strategy with AutoRetryHttpClient with DefaultServiceUnavailableRetryStrategy set to 0 for retry parameter. A better way would be to extend the AbstractHttpClient or implement HttpClient to expose the desired method.
Related
I am trying to build an http POST using the examples of Apache Components (4.3) - http://hc.apache.org/httpcomponents-client-4.3.x/tutorial/html/fluent.html. Unfortunately, I receive an error that I have not been able to find out how to solve.
I have used the former HttpClient before - so this is my first go with components.
Here is a snippet of the code:
String address = "http://1.1.1.1/services/postPositions.php";
String response = Request.Post(address)
.bodyString("Important stuff", ContentType.DEFAULT_TEXT)
.execute().returnContent().asString();
System.out.println(response);
and when I run that code I get an exception:
Exception in thread "main" java.lang.IllegalStateException: POST request cannot enclose an entity
at org.apache.http.client.fluent.Request.body(Request.java:299)
at org.apache.http.client.fluent.Request.bodyString(Request.java:331)
at PostJson.main(PostJson.java:143)
I have tried to build a form element as well and use the bodyForm() method - but I get the same error.
I had the same issue, the fix is to use Apache Client 4.3.1 which works.
It seems that the Request was changed:
in 4.3.1 they use public HttpRequestBase
in the latest release they use the package protected InternalHttpRequest
For the sake of completeness I am going to post the way to do it without using the Fluent API. Even if it doesn't answer the question "How to use fluent of Apache Components", I think it is worth to point out that the below, simplest case, solution works for versions which have the bug:
public void createAndExecuteRequest() throws ClientProtocolException, IOException {
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpPost httppost = new HttpPost(host);
httppost.setEntity(new StringEntity("Payload goes here"));
try (CloseableHttpResponse response = httpclient.execute(httppost)) {
// do something with response
}
}
In my case, downgrading was not an option, so this was the best solution.
I did some digging and can't see how it can work (you might have found a bug).
The error stems from line 300 in Request in the latest trunk version. There a check is done to see if this.request instanceof HttpEntityEnclosingRequest but that is never true because this.request is always set to an instance of InternalHttpRequest in the Request constructor at line 130, and InternalHttpRequest does not implement org.apache.http.HttpEntityEnclosingRequest`.
This problem has blocked our whole team half a day!
We use apache httpclient 4.3.x to post and get data from an storage server which provides http api. In order to improve performance, we used PoolingHttpClientConnectionManager:
public HttpClient createHttpClient() {
Registry registry = RegistryBuilder.create()....build();
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry);
connectionManager.setMaxTotal(50);
connectionManager.setDefaultMaxPerRoute(50);
CloseableHttpClient httpClient = HttpClients.custom()
.setConnectionManager(connectionManager)
.build();
return httpClient;
}
Then we hold an instance of the httpClient in our program, reuse it with every http request:
Global httpClient:
HttpClient httpClient = createHttpClient();
Post some data:
HttpPost httpPut = new HttpPost("...");
HttpResponse response = httpClient.execute(httpPut);
// Notice we get the response content here!
String content = EntityUtils.toString(response.getEntity());
System.out.println(content);
httpPut.releaseConnection();
response.close();
Then get:
HttpGet httpGet = new HttpGet("...");
// Blocked at this line !!!!
HttpResponse response = httpClient.execute(httpGet);
String content = EntityUtils.toString(response.getEntity());
System.out.println(content);
httpPut.releaseConnection();
response.close();
Please notice the line: // Blocked at this line !!!!
The program has blocked at that line and never go to next line. In debugging mode, I can see it has been blocked at:
SocketInputStream.socketRead0()
I've searched for a lot of questions and documents, but no lucky.
My colleage just fix it by setting NoConnectionReuseStrategy.INSTANCE:
HttpClients.custom()
.setConnectionManager(connectionManager)
// Following line fixed the problem, but why?
.setConnectionReuseStrategy(NoConnectionReuseStrategy.INSTANCE)
.build();
Now it doens't blocked, but why?
What does "reuse connection" mean? And is there performance issue by using NoConnectionReuseStrategy?
Thank you, guys~
I tried to reproduce the blocking http-get (also as an exercise for myself) but even without closing responses I could not get it to block. The ONLY time I managed to make the http-get block is by doing a response.getEntity().getContent() without reading from the returned InputStream and without closing the returned InputStream.
For my tests I used Tomcat 7.0.47 with two very simple servlets (one responding "OK" to a get, the other echoing a post) as a server. The client started 50 threads with each thread performing 30 alternating http-get and http-post request (total of 1500 requests). The client did not use the RegistryBuilder, instead the default one is used (created by the PoolingHttpClientConnectionManager itself).
About the NoConnectionReuseStrategy: by default (HttpClient created with HttpClients.createDefault(), I used org.apache.httpcomponents:httpclient:4.3.1) a connection pool is used with a maximum of 2 connections to 1 server. E.g. even if 5 threads are doing all kinds of requests at the same time to 1 server, the connection pool opens only 2 connections, re-uses them for all requests and ensures that 1 connection is used by 1 thread at any given time. This can have a very positive impact on client performance and significantly reduces load on the server. The only thing you must make sure is to call response.close() in a finally-block (this ensures the connection is returned to the connection pool). By using the NoConnectionReuseStrategy you basically disable the connection pool: for each request a new connection will be created. I recommend you enable debug-logging for category org.apache.http.impl.conn.PoolingHttpClientConnectionManager, it is very informative.
A note about httpPut.releaseConnection(): this does not actually release a connection, it only ensures that you can re-use the "httpPut" object in a next request (see the apidocs, follow the shown link). Also note that in your code for the "httpGet", you call releaseConnection() on "httpPut" instead of "httpGet".
Ran into this problem just a while back. In case someone else comes across this problem, this post might be useful.
I am using a Java Servlet to service my requests. When I wrote to the response stream using the PrintWriter instance my client blocked. Tried writing to the OutputStream directlyresponse.getOutputStream.write("myresponse") and it worked.
--Update--
Apologies for those who helped me, it turns out this is just a problem with Eclipse's debugger. After suspecting that it was leading me wrong, I placed down a couple of System.out.println to watch the variables, and according to them they ARE being changed, and that the debugger was just showing me old information for whatever reason. No clue why that's happening, but the important thing is that the code does apparently actually work.
I'm working on a method to share with twitter for an Android application, and I'm having errors when setting up the HttpURLConnection. I create the connection object as per usual, using the openconnection function of a url then casting it to a HttpURLConnection, and when I subsequently run SetRequestMethod("POST") on the connection, it does absolutely nothing. When I run the code in the debugger line by line, as I go through that line the request method just remains as the default ("GET"). Anyone have any idea as to why this may be happening? I'm getting the same problem with setDoOutput(true) also not changing anything. However, adding a request property does still work. I've been searching around and haven't been able to find anything on this problem, not even another person reporting these problems.
I am not sur whether using HttpURLConnection is the best here.
Did you try the following way?
// Building the POST request
final BasicNameValuePair message = new BasicNameValuePair("yourField", "yourContent");
final List<NameValuePair> list = new ArrayList<NameValuePair>(1);
list.add(message);
final HttpPost httppost = createHttpPost(UrlEncodedFormEntity(list));
// Building the HTTP client
final HttpParams httpParameters = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(httpParameters, YOUR_CHOSEN_CONN_TIMEOUT);
HttpConnectionParams.setSoTimeout (httpParameters, YOUR_CHOSEN_SO_TIMEOUT);
final HttpClient httpClient = new DefaultHttpClient(httpParameters);
// Execution of the POST request
final HttpResponse response = httpClient.execute(httppost);
This is the way I usually do, with no problems.
[EDIT: 04-25-2014] Apache's HttpClient was the best approach for Froyo and former versions. Now, according to this article from Android Developers Blog (written after this Q&A), it is better to use URLConnection.
I'm currently using HttpURLConnection to stream live content such as a radio broadcast. However it seems that using HttpClient is a better option since it's well supported by Android and it's a better implementation. Also, there seems to be a logic for automatic reconnection from a lost connection.
My problem is that I can't get this to work. It's always hanging when calling httpclient.execute(...).
What am I doing wrong?
HttpClient httpclient = new DefaultHttpClient();
HttpGet httpget = new HttpGet("http://208.76.243.123:7100");
HttpResponse response = httpclient.execute(httpget);
HttpEntity entity = response.getEntity();
Run it in debugger and when it hangs, call break. Then find the thread that is executing your code and see in stack trace where exactly it blocked. You will see if it blocked on IO or something else is happening. With that data it will be easier to identify the problem.
Are you sure your server understands the HTTP protocol? (I assume yes, it sounds like you had a different client working). It is possible the execute method is blocking because it has not seen a valid Response header yet.
You probably want entity.getContent() which will return a handle to a stream. See this question.
Sorry, I'm quite new to Java.
I've stumbled across HttpGet and HttpPost which seem to be perfect for my needs, but a little long winded. I have written a rather bad wrapper class, but does anyone know of where to get a better one?
Ideally, I'd be able to do
String response = fetchContent("http://url/", postdata);
where postdata is optional.
Thanks!
HttpClient sounds like what you want. You certainly can't do stuff like the above in one line, but it's a fully-fledged HTTP library that wraps up Get/Post requests (and the rest).
I would consider using the HttpClient library. From their documentation, you can generate a POST like this:
PostMethod post = new PostMethod("http://jakarata.apache.org/");
NameValuePair[] data = {
new NameValuePair("user", "joe"),
new NameValuePair("password", "bloggs")
};
post.setRequestBody(data);
// execute method and handle any error responses.
...
InputStream in = post.getResponseBodyAsStream();
// handle response.
There are a number of advanced options for configuring the client should you eventually required those.