Why http post on android fails over 3g? - android

i have an android application that makes an HTTP post request to a server containing some NameValuePairs, and It works just fine over any wifi network, but when i use the same http post over 3g, the server gets a http request with an empty body. Here is the code for the request
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(
3);
nameValuePairs.add(new BasicNameValuePair("Name", params[0]));
nameValuePairs.add(new BasicNameValuePair("DNI", params[1]));
nameValuePairs.add(new BasicNameValuePair("Token", params[2]));
URL url = new URL(URL_SERVER);
HttpURLConnection conn = (HttpURLConnection) url
.openConnection();
conn.setReadTimeout(30000);
conn.setConnectTimeout(50000);
conn.setRequestMethod("POST");
conn.setDoInput(true);
conn.setDoOutput(true);
OutputStream os = conn.getOutputStream();
BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(os, "UTF-8"));
writer.write(getQuery(nameValuePairs));
writer.flush();
writer.close();
os.close();
conn.connect();
int responseCode = conn.getResponseCode();
BufferedReader in;
if (responseCode == 404)
in = new BufferedReader(new InputStreamReader(
conn.getErrorStream()));
else
in = new BufferedReader(new InputStreamReader(
conn.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
Here is the code for the getQuery method
private String getQuery(List<NameValuePair> params)
throws UnsupportedEncodingException {
StringBuilder result = new StringBuilder();
boolean first = true;
for (NameValuePair pair : params) {
if (first)
first = false;
else
result.append("&");
result.append(URLEncoder.encode(pair.getName(), "UTF-8"));
result.append("=");
result.append(URLEncoder.encode(pair.getValue(), "UTF-8"));
}
return result.toString();
}
Any idea why this happens?
I have new info. I made a form to send the http post over the web browser. that form works great and sends perfectly the body over 3g on Windows phone and over wifi. But when I try to use the chrome of the android phone over 3g to send the http post, it arrives empty, and also if I try to send the http post from one computer connected to a hotspot of my android phone it fails. When i try with the same computer connected to a wifi network, no problem at all. This is so weird. Ideas?

My advice is to use Google's Volley library for networking. It is pretty much the best choice currently when it comes to networking on Android. It really should not be a 3G problem. If it is, you problem might be an isolated one.
Here you have some resources to look at(volley is really easy to use):
https://developers.google.com/events/io/sessions/325304728
https://developer.android.com/training/volley/index.html

Solved, the problem was that the server didn't read properly the requests that had multiple tcp datagrams, and looks like android split the tcp datagrams over 3g

Related

Is it possible to Enable TLS 1.2 in android 4.4

I have an existing android app which runs on Android EMDK TC70 device. Server team has upgraded the endpoints to the new server. When i try to change the endpoints to new endpoints requests are not going to backend server.
Server has been upgraded to TLS1.2.
In response i am getting an exception "SSL handshake Exception connection closed by PEER"
But when i run the same request in the Postman the response is fine.
If i run the same request in the normal android sample application the response is fine.
My problem is its not working on TC70 device.
TC70 device currently i have the OS version of 4.4 (not able to update)
Can you please help me. how to resolve the issue ?
HttpURLConnection con = (HttpURLConnection)obj.openConnection();
con.setRequestProperty("Accept", "application/json");
con.setRequestProperty("Content-Type", "application/json");
con.setRequestProperty ("Authorization", basicAuth);
// con.setRequestProperty("access-control-allow-origin", url);
//con.setRequestProperty("Content-Length","409");
con.setConnectTimeout(600000);// 60 sec
con.setReadTimeout(600000);
//con.setDoInput(true);
//con.setDoOutput(true);
String postJsonData = getJSonRequest(map);
con.setRequestProperty("Accept-Language", "en-US,en;q=0.5");
con.setDoOutput(false);
DataOutputStream wr = new DataOutputStream(con.getOutputStream());
wr.writeBytes(postJsonData);
wr.flush();
wr.close();
int responseCode;
responseCode = con.getResponseCode();
Log.e(TAG, String.valueOf(responseCode));
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
String output;
StringBuffer response = new StringBuffer();
try {
while ((output = in.readLine()) != null) {
response.append(output);
}
} catch (IOException e) {
e.printStackTrace();
}
in.close();

What am I doing wrong? My Timeout is not working

I have changed the Wi-Fi IP to not be able to connect.
I want that when the 5 seconds pass do something else but it waits about 20 seconds.
URL url = null;
HttpsURLConnection conn = null;
try {
url = new URL("MY_URL");
conn = (HttpsURLConnection) url.openConnection();
conn.setReadTimeout(3000);
conn.setConnectTimeout(5000);
conn.setRequestMethod("POST");
conn.setDoInput(true);
conn.setDoOutput(true);
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("msg", String.valueOf(jsonArray)));
OutputStream os = conn.getOutputStream();
BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(os, "UTF-8"));
writer.write(getQuery(params));
writer.flush();
writer.close();
conn.connect();
BufferedReader reader = new BufferedReader(new InputStreamReader((InputStream) conn.getContent(), "UTF-8"));
String response = reader.readLine();
From documentation
Warning: If the hostname resolves to multiple IP addresses, Android's default implementation of HttpURLConnection will try each in RFC 3484 order. If connecting to each of these addresses fails, multiple timeouts will elapse before the connect attempt throws an exception. Host names that support both IPv6 and IPv4 always have at least 2 IP addresses.
That means, if a host has "n" IP addresses involved, it will take n*milliseconds time instead milliseconds you defiend.

Android HttpUrlConnection erroor handling

I'm developing an Android app which works with server. I have POST request (using HttpURLConnection). Code is:
//setting URL to HttpURLConnection conn
conn.setReadTimeout(30000);
conn.setConnectTimeout(14000);
conn.setChunkedStreamingMode(0);
conn.setRequestMethod("POST");
conn.setDoInput(true);
conn.setDoOutput(true);
Uri.Builder builder = new Uri.Builder();
for (Map.Entry<String, String> entry : paramList.entrySet())
builder.appendQueryParameter(entry.getKey(), entry.getValue());
String query = builder.build().getEncodedQuery();
DataOutputStream os = new DataOutputStream(conn.getOutputStream());
BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(os, "UTF-8"));
writer.write(query);
writer.flush();
writer.close();
os.close();
responseCode = conn.getResponseCode(); // IOException!
BufferedReader in = new BufferedReader(
new InputStreamReader(conn.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
In case of error I need to show exact error message, for instance, "Connection timeout", or "Read timeout", or "Authorization problems" (for 401 status), etc.
How can I handle:
Connection timeout?
ReadTimeout?
And how can I get response code if it throws an IOException if server responses 4xx status? I read several questions here, but I didn't understand, how can I handle timeout errors and how can I get response code in case of IOException.

Android - How can I open a persistent HTTP connection that receives chunked responses?

I'm trying to establish a persistent HTTP connection to an API endpoint that publishes chunked JSON responses as new events occur. I would like to provide a callback that is called each time the server sends a new chunk of data, and keep the connection open indefinitely. As far as I can tell, neither HttpClient nor HttpUrlConnection provide this functionality.
Is there a way to accomplish this without using a TCP socket?
One solution would be to use a delimeter such as \n\n to separate each json event. You could remove blank lines from original json before sending. Calling setChunkedStreamingMode(0) allows you to read content as it comes in (rather than after the entire request has been buffered). Then you can simply go through each line, storing them, until a blank line is reached, then parse the stored lines as JSON.
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setChunkedStreamingMode(0);
conn.connect();
InputStream is = conn.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
StringBuffer sBuffer = new StringBuffer();
String line;
while ((line = reader.readLine()) != null) {
if (line.length() == 0) {
processJsonEvent(sBuffer.toString());
sBuffer.delete(0, sBuffer.length());
} else {
sBuffer.append(line);
sBuffer.append("\n");
}
}
As far as I can tell, Android's HttpURLConnection doesn't support receiving chunks of data across a persistent HTTP connection; it instead waits for the response to fully complete.
Using HttpClient, however, works:
HttpClient httpClient = new DefaultHttpClient();
try {
HttpUriRequest request = new HttpGet(new URI("https://www.yourStreamingUrlHere.com"));
} catch (URISyntaxException e) {
e.printStackTrace();
}
try {
HttpResponse response = httpClient.execute(request);
InputStream responseStream = response.getEntity().getContent();
BufferedReader rd = new BufferedReader(new InputStreamReader(responseStream));
String line;
do {
line = rd.readLine();
// handle new line of data here
} while (!line.isEmpty());
// reaching here means the server closed the connection
} catch (Exception e) {
// connection attempt failed or connection timed out
}

POST function for REST service returns empty response

I'm trying to do a post method for a REST service, but I'm not getting any response from server:
public JSONObject postValues (String strUrl, String strJsonArray) throws Exception{
JSONObject jsonObject = null;
URL url = new URL(strUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(10000);
conn.setConnectTimeout(15000);
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
strJsonArray = "data=" + strJsonArray;
Log.e("result",""+strJsonArray);
OutputStream os = conn.getOutputStream();
os.write(strJsonArray.getBytes());
os.flush();
conn.connect();
if (conn.getResponseCode() != 200) {
throw new RuntimeException("Failed : HTTP error code : "
+ conn.getResponseCode());
}
BufferedReader br = new BufferedReader(new InputStreamReader(
(conn.getInputStream())));
String output;
StringBuilder sb = new StringBuilder();
System.out.println("Output from Server .... \n");
while ((output = br.readLine()) != null) {
Log.e("output",output);
sb.append(output);
}
Log.e("output",sb.toString());
jsonObject = new JSONObject(sb.toString());
conn.disconnect();
return jsonObject;
}
When I see my logCat a get:
output {}
I know that the server is working right because I'm using the "advanced REST client" plugin of google chrome. If I call the URL manually (using the plugin of course)I get the desired answer:
{"message":"OK","code":200}
But if I try to use my function, my strJsonArray is inserted but I get an empty respond from server.
Is there anything wrong with my code?.
Everything looks good...
You could use Wireshark to capture the packets sent to and received from the server using an emulator and the chrome rest client. Then you can compare them and maybe find out what's wrong.
You could also check if theres something in the error stream (conn.getErrorStream()).

Categories

Resources