OkHttp doesn't reuse HTTPS/HTTP2 connections - java

Each time I make a new request, a new connection is open.
There isn't any connection reuse whatsoever.
What am I doing wrong?
I am using the latest OkHttp package (3.11.0).
My server is supporting HTTP/2. The request URLs are all HTTPS.
OkHttpClient client = new OkHttpClient();
try {
Request request = new Request.Builder().url(url).build();
Response response = client.newCall(request).execute();
mJSONstring = response.body().string();
} catch (IOException e) {
e.printStackTrace();
}

I found the reason: I was instantiating a new client each time.
If you want to reuse connections, you should use the same client instance for all the calls.

Related

Get java.net.SocketException: java.lang.IllegalStateException: No factory found. While trying to send POST request to HTTP server

I am writing an Android application in Android Studio which is sending a POST request to the server.
I have made a class for the HTTP connection:
public class PostTask extends AsyncTask {
#Override
protected Object doInBackground(Object[] objects) {
Requester requester = new Requester();
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost("https://dev-api.shping.com/serialization-service/reassignment/task");
HttpResponse response = null;
HttpHost httpproxy = new HttpHost("hmkproxy1.fmlogistic.fr",8080);
httpclient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, httpproxy);
try {
httppost.setHeader("authenticateit_identity_ticket","63eb8926-e661-42c1-998d-3f008665c8e5");
httppost.setHeader("cache-control","no-cache");
httppost.setHeader("content-type", "application/json");
StringEntity params = new StringEntity(requester.getJsonObject().toString());
httppost.setEntity(params);
// Execute HTTP Post Request
response = httpclient.execute(httppost);
System.out.println(response);
} catch (ClientProtocolException e) {
System.out.println("FUCK1");
} catch (IOException e) {
System.out.println(e);
}
return null;
}
}
I am connecting through a proxy. I get this exception while my app works: java.net.SocketException: java.lang.IllegalStateException: No factory found
Please help me, there is nearly no information about this exception on the internet. I tried to add some socket factories to my method, but it doesn't seems to work so I deleted them.
Thanks!
Remove android:networkSecurityConfig from manifest.

How to apply proper error handling of TimeOut for httpclient

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);
}
}

Connecting to backend server from app via HTTPS cause delays/timeouts

I'm developing an android app which connects to backend server via HTTPS. Everything is working properly when I use mobile data - no errors and other similar things. However, when I turn on WiFi and try to get some data from backend server I'm getting large delays (even 40 seconds) although I download just two lines of text, for example. I've also noticed that if I connect to backend server via HTTP, there is no problem using both mobile data and WiFi. I have tested many times if I set up SSL protocol properly and everything seems to be done properly.
I'm providing to you a piece of code, which is responsible for connecting with backend server from the app:
private boolean downloadData() {
try {
URI uri = new URI("https://www.example.com/resources/script/get_data.php");
HttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(uri);
httpPost.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
httpPost.setHeader("Pragma", "no-cache");
HttpResponse httpResponse = httpClient.execute(httpPost);
String result = EntityUtils.toString(httpResponse.getEntity());
if(result.equals("error")) {
return false;
}
result = result.replaceAll("\"", "\\\"");
JSONArray jsonArray = new JSONArray(result);
// code which receive and parse data from JSON
return true;
} catch (URISyntaxException e) {
e.printStackTrace();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
return false;
}
If you want to get some more information/pieces of code, write in comments.
Thanks for your help
You need to trace you requests by some monitoring program. After that you can see what node creates a delay. And pls show this data.

Post a request in java [duplicate]

This question already has answers here:
How to add parameters to api (http post) using okhttp library in Android
(9 answers)
Closed 6 years ago.
Recently I want use a search interface.But I am confused by the request body.
According to reference,when you need to search in their site,you can do like this:
curl -d "keyword=android" http://gankio.herokuapp.com/search
So how to post a this request in java rather than curl?
I have tried useing okhttp.
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
OkHttpClient client = new OkHttpClient();
String json = "keyword=android";
RequestBody body = RequestBody.create(JSON,json);
Request request = new Request.Builder()
.url("http://gankio.herokuapp.com/search")
.post(body)
.build();
try {
Response response = client.newCall(request).execute();
Log.d("TAG",response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
}
});
thread.start();`
I have solved this question.
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
OkHttpClient client = new OkHttpClient();
RequestBody requestBody = new FormBody.Builder().add("keyword", "android").build();
Request request = new Request.Builder()
.url("http://gankio.herokuapp.com/search")
.post(requestBody)
.build();
try {
Response response = client.newCall(request).execute();
Log.d("TAG", response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
}
});
thread.start();
You want to call the service using post request and form param, please use the below code:
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("http://gankio.herokuapp.com/search?keyword=android")
.post( RequestBody.create(MediaType.parse("application/json; charset=utf-8"), ""))
.build();
try {
Response response = client.newCall(request).execute();
System.out.println(response.toString());
System.out.println(response.body().string());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Response response = client.newCall(request).execute();
The service that you want to call does not need any body to pass, only it needs form parameter (keyword) with value (android), but you are trying to pass the parameter using the body, and this is your mistake
You can try using HttpUrlConnection from java.net
This link will explain HttpUrlConnection connection process.

Using Apache HttpClient how to set the TIMEOUT on a request and response

I need to set time out for the Http Request we make to a service (not a web service). We are using Apache HTTP Client. I have added these 2 lines of code to set the time out on request and response to the service.
HttpConnectionParams.setConnectionTimeout(params, 10000);
HttpConnectionParams.setSoTimeout(params, 10000);
1) Currently I have set 10 seconds as the timeout since I see the response coming from the service almost instantaneously. Should I increase or decrease the timing?
2) What will happen when response is takes more than 10 seconds? Will it throw exception and what exception will it be? Is there any thing else I need to add to set the time out in the below code.
public HashMap<String, Object> getJSONData(String url) throw Exception{
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpParams params = httpClient.getParams();
HttpConnectionParams.setConnectionTimeout(params, 10000);
HttpConnectionParams.setSoTimeout(params, 10000);
HttpHost proxy = new HttpHost(getProxy(), getProxyPort());
ConnRouteParams.setDefaultProxy(params, proxy);
URI uri;
InputStream data = null;
try {
uri = new URI(url);
HttpGet method = new HttpGet(uri);
HttpResponse response = httpClient.execute(method);
data = response.getEntity().getContent();
}
catch (Exception e) {
e.printStackTrace();
}
Reader r = new InputStreamReader(data);
HashMap<String, Object> jsonObj = (HashMap<String, Object>) GenericJSONUtil.fromJson(r);
return jsonObj;
}
I am guessing many people come here because of the title and because the HttpConnectionParams API is deprecated.
Using a recent version of Apache HTTP Client, you can set these timeouts using the request params:
HttpPost request = new HttpPost(url);
RequestConfig requestConfig = RequestConfig.custom()
.setSocketTimeout(TIMEOUT_MILLIS)
.setConnectTimeout(TIMEOUT_MILLIS)
.setConnectionRequestTimeout(TIMEOUT_MILLIS)
.build();
request.setConfig(requestConfig);
Alternatively, you can also set this when you create your HTTP Client, using the builder API for the HTTP client, but you'll also need to build a custom connection manager with a custom socket config.
The configuration example file is an excellent resource to find out about how to configure Apache HTTP Client.
The exceptions you'll see will be ConnectTimeoutException and SocketTimeoutException. The actual timeout values you use should be the maximum time your application is willing to wait. One important note about the read timeout is that it corresponds to the timeout on a socket read. So it's not the time allowed for the full response to arrive, but rather the time given to a single socket read. So if there are 4 socket reads, each taking 9 seconds, your total read time is 9 * 4 = 36 seconds.
If you want to specify a total time for the response to arrive (including connect and total read time), you can wrap the call in a thread and use a thread timeout for that. For example, I usually do something like this:
Future<T> future = null;
future = pool.submit(new Callable<T>() {
public T call() {
return executeImpl(url);
}
});
try {
return future.get(10, TimeUnit.SECONDS);
}
catch (InterruptedException e) {
log.warn("task interrupted", name);
}
catch (ExecutionException e) {
log.error(name + " execution exception", e);
}
catch (TimeoutException e) {
log.debug("future timed out", name);
}
Some assumptions made in the code above are: 1) this is in a function with a url parameter, 2) it's in a class with a name variable, 3) log is a log4j instance, and 4) pool is a some thread pool executor. Note that even if you use a thread timeout, you should also specify a connect and socket timeout on the HttpClient, so that slow requests don't eat up the resources in the thread pool. Also note that I use a thread pool because typically I use this in a web service so the thread pool is shared across a bunch of tomcat threads. You're environment may be different, and you may prefer to simply spawn a new thread for each call.
Also, I've usually see the timeouts set via member functions of the params, like this:
params.setConnectionTimeout(10000);
params.setSoTimeout(10000);
But perhaps your syntax works as well (not sure).

Categories