android http request execution is slow randomly - android

I'm using the below code to fetch some data from server: (it happens on button onclick)
#Override
protected ArrayList<Category> doInBackground(String... arg0) {
ArrayList<Category> result = new ArrayList<Category>();
JSONArray array = new JSONArray();
BufferedReader in = null;
try
{
HttpParams params = new BasicHttpParams();
params.setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
HttpClient httpclient = new DefaultHttpClient(params);
HttpGet request = new HttpGet();
URI website = new URI(_URL);
request.setURI(website);
HttpResponse response = httpclient.execute(request);
in = new BufferedReader(new InputStreamReader(
response.getEntity().getContent()));
String data = in.readLine();
array = new JSONArray(data);
for(int i = 0;i < array.length();i++)
{
JSONObject object = array.getJSONObject(i);
Category category = new Category(object.getInt("Id"), object.getString("Name"));
result.add(category);
}
}
catch(Throwable t)
{
Log.e("Error getting categories", t.getMessage());
}
return result;
}
the problem is that 8 out of 10 tries,it throws the following exception:
org.apache.http.conn.HttpHostConnectException: Connection to http://kiagallery.ir refused
and most of the times it takes a long time to fetch the data, but sometimes it's fast as a lightning bolt, the data is not big, here's the data that's supposed to be fetched at the moment:
[{"Id":44,"Name":"Collection 101"},{"Id":45,"Name":"local 01"}]
so my question is, how come sometimes it can fetch the data at reasonable speed and sometimes it throws an exception, could be the network speed? because my workplace got a terrible network, I also tried at home and the result was better but the exception occurred still once in a while
Additional Info: I used curl to fetch it and it was fast, paste the url in my browser and it was fast.

if you suspect the server-side , you can just remove the android stack from the equation and test directly in curl, using switches -V and 'time' to measure as much stuff as you want.
when you have investigated server directly and are no longer suspicious of server-side, you return to your android stack.
example POST on REST endpoint:
curl -X POST -H "X-Parse-Application-Id: ovv" -H "X-Parse-REST-API-Key: heoj" -H "X-Parse-Session-Token: i9ds" -H "Content-Type: application/json" --data #media1.json https://api.parse.com/1/classes/MediaItem

Related

Recieving HTML file as responce instead of JSON Object through get request

I am developing an android app where user logs on to his/her account. After logging in I will receive XSRF token and Laravel Session Id to recognise the specific user. I have to send these tokens for every request I send to the API's to get the appropriate information. But when I am sending the required details as shown in the image, I am getting HTMl file as response instead of getting JSON Object. I was seriously stuck at this problem. Correct Solution may take forward the whole app.
class RegisterConnection extends AsyncTask<String,String,JSONObject> {
protected JSONObject doInBackground(String... arg0) {
JSONObject output = new JSONObject();
DefaultHttpClient client = new DefaultHttpClient();
HttpConnectionParams.setConnectionTimeout(client.getParams(), 5000); //Timeout Limit
HttpResponse response = null;
try {
HttpGet get = new HttpGet(statsURL);
get.setHeader("Accept", "application/json");
CookieStore store = new BasicCookieStore();
BasicClientCookie cookie1 = new BasicClientCookie("XSRF-TOKEN", XSRF);
BasicClientCookie cookie2 = new BasicClientCookie("laravel_session", laravel);
store.addCookie(cookie1);
store.addCookie(cookie2);
client.setCookieStore(store);
response = client.execute(get);
if(response!=null){
InputStream in = response.getEntity().getContent();
String resultstring = Utilities.convertStreamToString(in);
Log.i("Result1", resultstring);
output = new JSONObject(resultstring);
Log.i("Result2", output.toString());
}
} catch(Exception e) {
e.printStackTrace();
try {
output.put("sai","error");
Log.i("MainActivity", output.toString());
} catch (JSONException e1) {
e1.printStackTrace();
}
return output;
}
return output;
}
These are the server requirements
http://imgur.com/OY9Q673
This is the Output received
http://imgur.com/IB5AEcT
As far as I can tell, there is nothing wrong with your Android client code.
You are getting HTML from the server so the main reason could be that your Laravel server is rendering the views and sending you back html instead of JSON. Instead of rendering the views on the server, you should send JSON response on your Laravel server side.
Add Jsoup dependency in your gradle file
implementation 'org.jsoup:jsoup:1.11.2'
Document document = Jsoup.parse("http://imgur.com/IB5AEcT");
Elements el = doc.select("button");
Log.i("..........",""+el.attr("data-invite-details"));
Jsoup tutorial
http://jsoup.org/apidocs/org/jsoup/Jsoup.html

how to use URL to post data with HttpClient in android

I have to send/post some data to .svc Web Service that basically connect to remote database. I'm using JSONStringer to send the data but every time response status is false. My data is not sent. How to use HttpPost in Android . Can someone help me how to solve this .
Here is my webservice code
String namespace = "http://103.24.4.60/xxxxx/MobileService.svc";
public void ActivityUpload( final String strCurrentDateTime, final String strTitle, final String replaceDescChar, final String editedHashTag)
{
new AsyncTask<String, Void, String>()
{
#Override
protected String doInBackground(String... arg0)
{
String line = "";
try
{
Log.e("ActionDate "," = "+ strCurrentDateTime);
Log.e("ActivityId"," = "+strActivityId);
Log.e("UserId"," = "+str_UserId);
Log.e("ObjectId"," = "+strVessId);
Log.e("Name"," = "+strTitle);
Log.e("Remark"," = "+replaceDescChar);
Log.e("Status"," = "+"PENDING");
Log.e("Type"," = "+strType);
Log.e("starflag"," = "+0);
Log.e("HashTag"," = "+editedHashTag);
Log.e("Authentication_Token"," = "+str_Authentication_Token);
// make web service connection
HttpPost request = new HttpPost(namespace + "/Upd_Post_Activity");
request.setHeader("Accept", "application/json");
request.setHeader("Content-type", "application/json");
// Build JSON string
JSONStringer TestApp = new JSONStringer().object()
.key("ActionDate").value(strCurrentDateTime)
.key("ActivityId").value(strActivityId)
.key("UserId").value(str_UserId)
.key("ObjectId").value(strVessId)
.key("Name").value(strTitle)
.key("Remark").value(replaceDescChar)
.key("Status").value("PENDING")
.key("Type").value(strType)
.key("starflag").value("0")
.key("HashTag").value(editedHashTag)
.key("Authentication_Token").value(str_Authentication_Token).endObject();
StringEntity entity = new StringEntity(TestApp.toString());
Log.d("****Parameter Input****", "Testing:" + TestApp);
request.setEntity(entity);
// Send request to WCF service
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpResponse response = httpClient.execute(request);
Log.d("WebInvoke", "Saving: " + response.getStatusLine().toString());
// Get the status of web service
BufferedReader rd = new BufferedReader(new InputStreamReader(
response.getEntity().getContent()));
// print status in log
while ((line = rd.readLine()) != null) {
Log.d("****Status Line***", "Webservice: " + line);
}
} catch (Exception e) {
e.printStackTrace();
}
return line;
}
}.execute();
}
Here is input Parameter.
****Parameter Input****﹕ Testing:{"ActionDate":"2016-01-21%2014:20:43%20PM","ActivityId":"120160119180421058","UserId":"125","ObjectId":"1","Name":"Title2","Remark":"Test%20two","Status":"PENDING","Type":"3","starflag":"0","HashTag":"990075","Authentication_Token":"6321D079-5B28-4F3F-AEE7-D59A1B9EFA59"}
Thanks in advanced.
realize android httpclients are in process of deprecation ( in favor of httpsurlconnection ) but, these httpclients are still used pretty widely. On gradle builds, regard the deprication, and with small dependency lib tweeks , httpclient may be used for some time still.
( still gonna use httpclient ? )
Put android aside for a min.
learn how to CURL with JSON body for tests that show you what you EXACT JSON in body and exact HEADERS you will need to get success http result to a post ... ref here
Once you have that you can then go about transferring your curl test's components over to android.httpclient.exec.POST using httpclient of your choice.
Set the same group of Headers you had over in curl tests in your android post. apache.httpclient sample
2.a. make sure that default list of headers from the clients 'request' constructor does NOT include by default some headers you DO NOT want... In order to assure of this ,you probably will need to turn on HEADER logging for your client.... java example logger . remove unnecessary headers included by the framework constructor of POST.
2.b android logger (WIRE, HEADERS) is diff from and may take some digging , depend on what client is in use.
with the same headers as curl tests, set the http.posts request.entity to either a string or a properly encoded array of bytes containing the same JSON body used in the curl tests.
3.A. depending on the JSON lib, create your message objects and then convert the objects to some friendly type for enclosure in an entity for the post ie use a 'writer' to convert objects to a serialized string with the JSON.
reqRole = new ObjectMapper().createObjectNode();
reqRole.put("__type", "Pointer");
reqRole.put("className", "_Role");
reqRole.put("objectId", roleId);
rootOb.put("requestedRole", reqRole);
rootOb.put("requestedBy",usersArr);
StringWriter writer = new StringWriter();
try {
new ObjectMapper().writeValue(writer, rootOb)
..
String http-post-str=writer.toString();
3.B. wrap the string with json in the POST request...
httpPost.setEntity(new StringEntityHC4(http-post-str));
exec the request and youll get the same results you got in curl because the headers are same or nearly same and the body is the same , encoded string of json. same input = same result

Android HttpUrlConnection: Post Multipart

I'm trying to post a test File to a spring rest servlet deployed on tomcat using Android. I'm developing on Android 4.1.2, but I have verified same problem on 4.0.3.
The problem is that the file upload requires a very long time (about 70 seconds for a 4MB file), also in local network. The time is equiparable using a 3g connection. I've excluded that it could be a server problem: executing the same call with curl it takes 1 / 2 seconds, and using apache as backend results are the same.
Using HttpClient works fine.
I'm using Spring Android RestClient 1.0.1.RELEASE and, given Android version and the fact that I'm not overriding default behaviour, it uses HttpUrlConnection instead of HttpClient to make http requests.
I have also implemented my custom ClientHttpRequestFactory in order to manipulate some details of SSL connection and I have defined my own implementation of ClientHttpRequestInterceptor in order to modify authentication header.
I have also set setBufferRequestBody(false) in order to avoid OutOfMemoryException on big files. But this property have no effects on time required.
MyClientHttpRequestFactory:
public class MyClientHttpRequestFactory extends SimpleClientHttpRequestFactory{
#Override
protected void prepareConnection(HttpURLConnection connection, String httpMethod) throws IOException {
super.prepareConnection(connection, httpMethod);
connection.setConnectTimeout(240 * 1000);
connection.setReadTimeout(240 * 1000);
if ("post".equals(httpMethod.toLowerCase())) {
setBufferRequestBody(false);
}else {
setBufferRequestBody(true);
}
}
#Override
protected HttpURLConnection openConnection(URL url, Proxy proxy) throws IOException {
final HttpURLConnection httpUrlConnection = super.openConnection(url, proxy);
if (url.getProtocol().toLowerCase().equals("https")
&&
settings.selfSignedCert().get())
{
try {
((HttpsURLConnection)httpUrlConnection).setSSLSocketFactory(getSSLSocketFactory());
((HttpsURLConnection)httpUrlConnection).setHostnameVerifier(new NullHostnameVerifier());
} catch (Exception e) {
MyLog.e(LOG_TAG, "OpenConnection", e);
}
}
return httpUrlConnection;
}
MyClientHttpRequestInterceptor:
public class MyClientHttpRequestInterceptor implements ClientHttpRequestInterceptor {
#Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
final HttpHeaders headers = request.getHeaders();
headers.setAuthorization(new HttpBasicAuthentication( settings.username().get(), settings.password().get()));
if (settings.enable_gzip().get()) {
headers.setAcceptEncoding(ContentCodingType.GZIP);
}
return execution.execute(request, body);
}
}
And here my Rest call:
List<ClientHttpRequestInterceptor> interceptors = Arrays.asList((ClientHttpRequestInterceptor)myClientHttpRequestInterceptor);
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new FormHttpMessageConverter());
restTemplate.getMessageConverters().add(new StringHttpMessageConverter());
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
restTemplate.setInterceptors(interceptors);
MultiValueMap<String, Object> parts = new LinkedMultiValueMap<String, Object>();
parts.add("file", new FileSystemResource("/sdcard/test/4MB_file"));
HttpEntity<MultiValueMap> requestEntity = new HttpEntity<MultiValueMap>(parts);
restTemplate.exchange(myUrl, HttpMethod.POST, requestEntity, Integer.class).getBody();
}
Looking at Spring Android source code, the next lines of code my request is passing through are:
public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException {
HttpURLConnection connection = openConnection(uri.toURL(), this.proxy);
prepareConnection(connection, httpMethod.name());
if (this.bufferRequestBody) {
return new SimpleBufferingClientHttpRequest(connection);
} else {
return new SimpleStreamingClientHttpRequest(connection, this.chunkSize);
}
}
Because of this.bufferRequestBody is false, return new SimpleStreamingClientHttpRequest(connection, this.chunkSize); is executed (with chunkSize = 0)
SimpleStreamingClientHttpRequest(HttpURLConnection connection, int chunkSize) {
this.connection = connection;
this.chunkSize = chunkSize;
// Bugs with reusing connections in Android versions older than Froyo (2.2)
if (olderThanFroyo) {
System.setProperty("http.keepAlive", "false");
}
}
and then:
ClientHttpRequest delegate = requestFactory.createRequest(request.getURI(), request.getMethod());
delegate.getHeaders().putAll(request.getHeaders());
if (body.length > 0) {
FileCopyUtils.copy(body, delegate.getBody());
}
return delegate.execute();
From here is all android subsystem I think..
I have dumped tcp traffic and analyzed it:
POST /urlWherePost HTTP/1.1
Content-Type: multipart/form-data;boundary=nKwsP85ZyyzSDuAqozCTuZOSxwF1jLAtd0FECUPF
Authorization: Basic xxxxxxxxxxxxxxxxxxxxxxxxxx=
Accept-Encoding: gzip
User-Agent: Dalvik/1.6.0 (Linux; U; Android 4.1.2; sdk Build/MASTER)
Host: 192.168.168.225:8080
Connection: Keep-Alive
Content-Length: 4096225
--nKwsP85ZyyzSDuAqozCTuZOSxwF1jLAtd0FECUPF
Content-Disposition: form-data; name="file"; filename="4MB_file"
Content-Type: application/octet-stream
Content-Length: 4096000
I've tryed to re-create similar request with curl:
curl --verbose
-H "Connection: Keep-Alive"
-H "Content-Type: multipart/form-data"
-H "Accept-Encoding: gzip"
-H "Content-Disposition: form-data; name=\"file\"; filename=\"4MB_file\""
-H "Content-Type: application/octet-stream"
--user xxx:xxx
-X POST
--form file=#4MB_file
http://192.168.168.225:8080/urlWherePost
but with curl the post is ok.
Posting json data is not a problem (maybe small body size). But when I try to send "big" files the time increase.
Looking in DDMS shell, on Network Statistics I've also found that the network throughput is never over 250kb in TX. There seems to be a bootleneck, but how to investigate it? Where I can look, which parameter can I change?
Thank you for any suggestion!
Have you tried using the MultipartEntity method? I had the same problem when downloading big amounts of JSON data from the server, but I switched to this method and caught all the data that the server provided me.
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost("http://myurl.com");
try {
MultipartEntity entity = new MultipartEntity();
entity.addPart("type", new StringBody("json"));
entity.addPart("data", new JSONObject(data));
httppost.setEntity(entity);
HttpResponse response = httpclient.execute(httppost);
} catch (ClientProtocolException e) {
} catch (IOException e) {
} catch (JSONException e){
}
To upload big files, You can use this library android-async-http
For simple and easy to use, I recommend this lib https://github.com/koush/ion.
I use it on my project and it works perfectly.

Trouble sending JSON Post Android

It has been a while since I programmed for Android and I have lost all my previous work which had the code in it I am having problems with. I am developing an app for both Android and iPhone which connect to the same server to download data. All is well in the iPhone version but on Android when I hit the server with the post data containing the method name I would like to to run on the server it seems that the data is not added to the request.
Why is the POST not working in this request for Android but does for the iPhone version of the app?
Here is the code I am using:
public static void makeRequest() throws Exception {
Thread t = new Thread() {
public void run() {
Looper.prepare(); //For Preparing Message Pool for the child Thread
HttpClient client = new DefaultHttpClient();
HttpConnectionParams.setConnectionTimeout(client.getParams(), 10000);
HttpResponse response;
HttpEntity entity;
JSONObject json = new JSONObject();
try {
HttpPost post = new HttpPost("http://divisi.co.uk/rest/requesthandler.php");
json.put("method", "getEventListData");
StringEntity se = new StringEntity(json.toString());
se.setContentType(new BasicHeader(HTTP.CONTENT_TYPE, "application/json"));
post.setEntity(se);
response = client.execute(post);
entity = response.getEntity();
String retSrc = EntityUtils.toString(entity);
JSONObject result = new JSONObject(retSrc); //Convert String to JSON Object
if(result.getString("SC") == "200"){
JSONArray data = result.getJSONArray("data");
}
else{
}
} catch(Exception e) {
e.printStackTrace();
}
Looper.loop(); //Loop in the message queue
}
};
t.start();
}
The response I get mack from the server is:
{"data":{"scalar":""},"SC":405,"timestamp":1363788265}
Meaning the method name was not found, i.e. not posted in my request to the server.
heres an example of how i do things like this:
HttpClient httpClient = new DefaultHttpClient();
HttpPost postRequest = new HttpPost("http://divisi.co.uk/rest/requesthandler.php");
MultipartEntity reqEntity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
reqEntity.addPart(new FormBodyPart("method", new StringBody("getEventListData")));
reqEntity.addPart(new FormBodyPart("NEED_A_KEY_HERE", new StringBody("" + json.toString())));
postRequest.setEntity(reqEntity);
HttpResponse response = httpClient.execute(postRequest);
JSONObject responseDict = new JSONObject(EntityUtils.toString(response.getEntity()));
allow this is your "http://divisi.co.uk/rest/requesthandler.php" page code, then in android you can use this... you don't allow post in your URL,
use fiddler on your sever side. see if the http message is correct. it seems your sever side problem, can you show us your sever side code which receive and parse json.
If the server can't read your request try to remove:
se.setContentType(new BasicHeader(HTTP.CONTENT_TYPE, "application/json"));
It will use the mime type defaults HTTP.PLAIN_TEXT_TYPE i.e. "text/plain".
I don't see any other possibility, if your code is the one you posted and not a more complicated input JSON object.
Your code to set the POST body may be just fine. I think the problem may be with your web service. Try using something like Rested or curl to manually make the call to your server. I made exactly the same request you are making, including with and without the POST body, and I got the same response from your server:
{"data":{"scalar":""},"SC":405,"timestamp":1365704082}
Some things that may be tripping you up:
JSONObject result = new JSONObject(retSrc); //Convert String to JSON Object
if(result.getString("SC") == "200"){
JSONArray data = result.getJSONArray("data");
}
Here, you are comparing the string "405" to "200" using ==, when you should first do a null check and then use .equals("200") instead. Or, use result.getInt("SC") == 200 since this is an integer type in your response JSON.
Also, the "data" entity from your server response is not actually coming back as a JSON array. You should use getJSONObject("data") instead.
Additionally, it's always a good idea to externalize your strings.
Here's how the code should look:
public static final String JSON_KEY_SC = "SC";
public static final String JSON_KEY_DATA = "data";
...
JSONObject result = new JSONObject(retSrc); //Convert String to JSON Object
String sc = result.getString(JSON_KEY_SC);
if (sc != null && sc.equals("200")) {
JSONObject data = result.getJSONObject(JSON_KEY_DATA);
}
else {
...
}

Http Post Request in Android won't return appropriate data?

Okay, so I was trying to send Http Post Requests to this one site, and I sniffed the sent request with wireshark thus getting the text data from the post request of this site. I used this in a stock Java application, and it worked perfectly fine. I could use the post method regularly with no problem whatsoever, and it would return the appropriate website. Then I tried doing this with Android. Instead of returning the actual html data after executing the post request, it returns the regular page html data untouched. It DOES send a post request (sniff with wireshark again), it just doesn't seem to get the appropriate response. I took the exact same method used from another one of my projects, which worked perfectly fine in that project, and pasted it into my new project. I added the INTERNET user permission in Android, so there's nothing wrong with that. The only visible difference is that I used NameValuePairs in the other one (the one that worked) and in this one I'm directly putting the string into a StringEntity without encoding (using UTF-8 encoding screws up the String though). I used this exact same line of text in regular Java like I said, and it worked fine with no encoding. So what could be the problem? This is the code:
public static String sendNamePostRequest(String urlString) {
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(urlString);
StringBuffer sb = new StringBuffer();
try {
post.setEntity(new StringEntity(
"__EVENTTARGET=&__EVENTARGUMENT=&__VIEWSTATE=%2FwEPDwULLTE3NDM5MzMwMzRkZA%3D%3D&__EVENTVALIDATION=%2FwEWBAL%2B%2B4CfBgK52%2BLYCQK1gpH7BAL0w%2FPHAQ%3D%3D&_nameTextBox=John&_zoekButton=Zoek&numberOfLettersField=3"));
HttpResponse response = client.execute(post);
HttpEntity entity = response.getEntity();
BufferedReader br = new BufferedReader(new InputStreamReader(
entity.getContent()));
String in = "";
while ((in = br.readLine()) != null) {
sb.append(in + "\n");
}
br.close();
} catch (Exception e) {
e.printStackTrace();
}
return sb.toString();
}
Can you see what's wrong here?

Categories

Resources