I'm doing a lot of http calls in my Android application. The http calls are synchronous for the most part. Every once in a while I'll get many 403 forbidden responses in a row, hitting the same URL. I do a login call directly before the call that results in a 403. The login call returns 200 ok. The 403s also happen more on newer Android platforms.
How I'm creating the client:
// Create and initialize HTTP parameters
HttpParams params = new BasicHttpParams();
ConnManagerParams.setMaxTotalConnections(params, 200);
ConnPerRoute cpr = new ConnPerRoute() {
public int getMaxForRoute(HttpRoute httpRoute) {
return 50;
}
};
ConnManagerParams.setMaxConnectionsPerRoute(params, cpr);
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
// Create and initialize scheme registry
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
// Create an HttpClient with the ThreadSafeClientConnManager.
ClientConnectionManager cm = new ThreadSafeClientConnManager(params, schemeRegistry);
_client = new DefaultHttpClient(cm, params);
The http call:
CookieStore cookie_store = HttpSupport.getCookieStoreInstance();
HttpContext http_context = HttpSupport.getHttpContextInstance();
HttpGet get = new HttpGet(StaticFields.DEVICES_RESOURCE);
http_context.setAttribute(ClientContext.COOKIE_STORE, cookie_store);
response = client.execute(get, http_context);
status_code = response.getStatusLine().getStatusCode();
I'm using a static CookieStore and HttpContext contained in my class HttpSupport.
Related
I am trying to call my RESTful WCF service over https on Android. I keep getting a 401: unauthorized error whenever I make the call. The other parts of my code work, ive tested it locally.
Here is the pertinent code:
// http scheme
schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
// https scheme
schemeRegistry.register(new Scheme("https", new EasySSLSocketFactory(), 443));
credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT),
new UsernamePasswordCredentials("user", "pass"));
clientConnectionManager = new ThreadSafeClientConnManager(params, schemeRegistry);
context = new BasicHttpContext();
context.setAttribute("http.auth.credentials-provider", credentialsProvider);
HttpGet request = new HttpGet(SERVICE_URI + URL1 + EID);
request.setHeader("Accept", "application/json");
request.setHeader("Content-type", "application/json");
DefaultHttpClient client = new DefaultHttpClient(clientConnectionManager, params);
client.setCredentialsProvider(credentialsProvider);
HttpResponse response = client.execute(request, context);
HttpEntity responseEntity = response.getEntity();
EasySSLSocketFactory uses an implementation of X509TrustManager. I know that code works as well. Can someone please provide some advice. Nothing I have found works correctly.
Turns out, HttpClient doen't support NTLM authentication out of the box (im using IIS with windows auth). This link gave me everything I needed. Just copy and paste and forget about it.
http://hc.apache.org/httpcomponents-client-ga/ntlm.html
I have massive performance problems with the execute method of the execute() method of the HttpDefaultClient.
I'm currently using this to post data to a Server, receiving JSON and deserialize the data. A call takes 8s to 30s on my phone. If I switch to Wifi (it's pretty fast, the same call takes 300ms on my PC) it takes 3s to 8s. At least 90% of that time is spend in the execute method.
Is use this code:
HttpPost post = new HttpPost(DEST_URL);
HashMap<String, String> params = req.getPostParams();
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
for (String key : params.keySet()) {
nameValuePairs.add(new BasicNameValuePair(key, params.get(key)));
}
post.setEntity(new UrlEncodedFormEntity(nameValuePairs));
post.setHeader(new BasicHeader(HTTP.CONTENT_TYPE, "application/json"));
HttpResponse response = httpClient.execute(post); // very slow!
return response;
We also develop an iOS app which is able to do the same within 1 to 2s. Is there a quicker way for http (https in the future)?
Creating the client like this:
HostnameVerifier hostnameVerifier = org.apache.http.conn.ssl.SSLSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER;
final SSLSocketFactory socketFactory = SSLSocketFactory
.getSocketFactory();
socketFactory
.setHostnameVerifier((X509HostnameVerifier) hostnameVerifier);
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
registry.register(new Scheme("https", socketFactory, 443));
HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier);
HttpParams params = new BasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
HttpClient client = new DefaultHttpClient(params);
Using: HTC Wildfire, Android 2.2.1
codes above works fine.
if i create an httpclient the following way:
DefaultHttpClient httpClient = new DefaultHttpClient();
// httpclient
httpClient.getParams().setParameter(
CoreConnectionPNames.CONNECTION_TIMEOUT, mConnectionTimeOut);
httpClient.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT,
mSocketTimeOut);
for first time to post data to server and got response , it cost me 10--20 seconds.
but if i create an HttpClient following the answer above.
when first time to post data to server and got response , it cost just 4 seconds,and i think it works fine .
HttpParams params = new BasicHttpParams();
ConnManagerParams.setMaxConnectionsPerRoute(params, new ConnPerRouteBean(100));
ConnManagerParams.setMaxTotalConnections(params, 100);
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setUseExpectContinue(params, false);
HttpProtocolParams.setContentCharset(params, HTTP.DEFAULT_CONTENT_CHARSET);
HttpConnectionParams.setConnectionTimeout(params, CONNECTION_TIMEOUT);
HttpConnectionParams.setSoTimeout(params, REQUEST_TIMEOUT);
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), PORT));
ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager(params, registry);
client = new DefaultHttpClient(cm, params);
HttpClientParams.setCookiePolicy(client.getParams(), CookiePolicy.BROWSER_COMPATIBILITY);
When my app waits for several seconds, the next post will be failed because of the ClientProtocolException.
By wireshark, I find that android also use the previous tcp socket to execute the post, but that socket is ended with a FIN from the server. And the next several posts will succeed because a new socket establish.
is there anyone know how to solve the problem??
I had a similar problem. Try adding this line :
System.setProperty("http.keepAlive", "false");
before you make the connection. Might solve your problem.
I have implemented HTTP Post to post data to the backend. How do I implement HTTPS in Android (I have already configured the backend for https)?
I googled and found some solutions:
Secure HTTP Post in Android
and tried them but I do not receive any data in the backend.
Is it the correct way to implement? Is there any other method?
Below is my code snippet:
File file = new File(filepath);
HttpClient client = new DefaultHttpClient();
//String url = "http://test.....;
String url = "https://test......";
HttpPost post = new HttpPost(url);
FileEntity bin = new FileEntity(file, url);
post.setEntity(bin);
HttpResponse response = client.execute(post);
HttpEntity resEntity = response.getEntity();
Basically I am using fileentity to do a HTTPPost. Now I want to do this over https. After implementing https over at the backend I just modified http to https in the url and tested again. And it is not working.
Any idea how do i resolve this?
Thanks In Advance,
Perumal
Make sure your http client supports the SSL socket:
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
schemeRegistry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
HttpParams params = new BasicHttpParams();
ClientConnectionManager manager = new ThreadSafeClientConnManager(params, schemeRegistry);
HttpClient httpsClient = new DefaultHttpClient(manager, params);
and use this client to execute your POST request:
HttpPost post = new HttpPost("https://www.mysecuresite.com");
post.setHeader("Content-Type", "application/x-www-form-urlencoded");
post.setEntity(new StringEntity("This is the POST body", HTTP.UTF_8));
HttpResponse response = httpsClient.execute(post);
I'm using a ThreadSafeClientConnManager to perform simultaneous requests in background threads on Android, set up with:
HttpParams params = new BasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, HTTP.DEFAULT_CONTENT_CHARSET);
HttpProtocolParams.setUseExpectContinue(params, true);
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
registry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
ClientConnectionManager connman = new ThreadSafeClientConnManager(params, registry);
client = new DefaultHttpClient(connman, params);
And executing requests with (note that I'm using outh-signpost):
HttpGet request = new HttpGet("https://" + API_HOST + "/" + API_VERSION + path);
OAuthConsumer consumer = new CommonsHttpOAuthConsumer(key, secret);
consumer.sign(request);
HttpResponse response = client.execute(request);
The problem is that after a while I start getting
java.net.SocketException: The operation timed out
Do I need to do something to explicitly release the connection after the request?
From the usage guide of apache httpclient, you need to make sure to consume all content on any pooled resource to guarantee it returns to the pool to be available for other threads later on -
http://hc.apache.org/httpcomponents-core-4.0.1/tutorial/html/fundamentals.html#d0e244
In case there's an exception thrown by the underlying library, it is best to abort the HttpMethod that you were trying to run, in which case the connection will be terminated.