HttpURLConnection POST-request throws IOException - java

I'm trying to make a POST-request using android HttpUrlConnection. First I use the example for GET-request from here:
http://developer.android.com/training/basics/network-ops/connecting.html#http-client
It works perfectly (for example I get google.com page). Then I make some changes to make a POST-request: change the request method on POST:
conn.setRequestMethod("POST");
and add this code (got from here: http://developer.android.com/reference/java/net/HttpURLConnection.html):
conn.setDoOutput(true);
conn.setChunkedStreamingMode(0);
OutputStream out = new BufferedOutputStream(conn.getOutputStream());
out.close();
So now the method downloadUrl looks like this:
private String downloadUrl(String myurl) throws IOException {
InputStream is = null;
// Only display the first 500 characters of the retrieved
// web page content.
int len = 500;
try {
URL url = new URL(myurl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(10000 /* milliseconds */);
conn.setConnectTimeout(15000 /* milliseconds */);
conn.setDoInput(true);
conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.setChunkedStreamingMode(0);
OutputStream out = new BufferedOutputStream(conn.getOutputStream());
out.close();
// Starts the query
conn.connect();
int response = conn.getResponseCode();
Log.d(DEBUG_TAG, "The response is: " + response);
is = conn.getInputStream();
// Convert the InputStream into a string
String contentAsString = readIt(is, len);
return contentAsString;
// Makes sure that the InputStream is closed after the app is
// finished using it.
} finally {
if (is != null) {
is.close();
}
}
}
And it always throws IOException. Could you help me, what is wrong?

It's because Android won't let you start a network connection on the main UI thread. You have to start a background thread (use AsyncTask) and do it from there.
More detail in this question.

I've sold this problem: the thing was the server didn't accept POST-requests on the selected URL. Changing URL (and server) led to successful request without throwing an exception.

Related

Persisting the same HttpURLConnection to send multiple JSON lists separately: what should ContentLength be?

Example problem:
I have an initial list of size 1000.
I want to POST the data of this list to a URL in 10 HTTP requests, where each request writes a ("sublist") of size 100 (since 1000 / 10 = 100).
Now I want to do the above using Java's HttpURLConnection, I have this method:
private static HttpURLConnection open(String endpoint) throws IOException {
URL url = new URL(endpoint);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setConnectTimeout(5000);
connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
connection.setDoOutput(true);
connection.setDoInput(true);
// Should I also set Content-Length? Why or why not?
connection.setRequestMethod("POST");
return connection;
}
My issue is that I don't know what the content length should be. Given the example above, should it be 1000 (the total size of the list fetched)? Or should it be 100 (the size of an individual list that will be sent throughout the session)? Note that I wish for the connection to be persistent; no need to open a new connection for every list to be sent.
For reference, my function that does the POST looks like the below:
private static int post(String endpoint, String payload) throws IOException {
int response;
try {
HttpURLConnection connection = open(endpoint, payload.length());
try (BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(connection.getOutputStream()))) {
writer.write(payload);
}
try (InputStream is = connection.getInputStream()) {
IOUtils.consume(is);
} catch (IOException e) {
InputStream es = connection.getErrorStream();
IOUtils.consume(es);
es.close();
}
response = connection.getResponseCode();
System.out.println(String.format("Sent batch with response code %d.", response));
} catch (IOException e) {
throw new IOException(e);
}
return response;
}

How to close a persistent HTTP Connection without reading

I have an URLConnection which I want to cancel depending on the response code without reading any data. I closely followed the android training to build the following minimal example which
floods the server with requests since no connection is ever released back to the handle pool for reuse
private String downloadUrl(String myurl) throws IOException {
InputStream is = null;
try {
URL url = new URL(myurl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(10000 /* milliseconds */);
conn.setConnectTimeout(15000 /* milliseconds */);
conn.setRequestMethod("GET");
conn.setDoInput(true);
// Starts the query
conn.connect();
int response = conn.getResponseCode();
Log.d(TAG, "The response code is: " + response);
is = conn.getInputStream();
// Do not read anything //String contentAsString = readIt(is, len);
String contentAsString = "notReadingAnything";
return contentAsString;
} finally {
if (is != null) {
is.close();
}
}
}
private class DownloadWebpageTask extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... urls) {
try {
String result = new String();
for (int i=0; i<100; i++) {
result += downloadUrl(urls[0]);
}
return result;
} catch (IOException e) {
return "Unable to retrieve web page. URL may be invalid.";
}
}
#Override
protected void onPostExecute(String result) {
Log.d(TAG, "The response is: " + result);
}
}
Despite the docs explicitly stating
But if the response body is long and you are not interested in the rest of it after seeing the beginning, you can close the InputStream
the server quickly reaches its maximum number of connections (50) and goes to 99% workload if I don't read the stream but works fine if I do read it. What is my mistake?
EDIT: Failed solution attempts so far (thanks to #Blackbelt for most of them)
calling conn.disconnect() in the finally block
calling conn.disconnect() instead of is.close() in the finally block
Setting System.setProperty("http.keepAlive", "false"); before the first call
Setting conn.setRequestProperty("Connection", "Close"); before connecting
Setting "{enable_keep_alive", "no"} on the used backend server (Civetweb)
you should call disconnect() too. Accordingly to the documentation
Disconnect. Once the response body has been read, the
HttpURLConnection should be closed by calling disconnect().
Disconnecting releases the resources held by a connection so they may
be closed or reused.
InputStream is = null;
HttpURLConnection conn = null;
try {
URL url = new URL(myurl);
conn = (HttpURLConnection) url.openConnection();
} finally {
if (is != null) {
is.close();
}
if (conn != null) {
conn.disconnect();
}
}
if you still are experiencing issues, is also possible that the bug is backend side

HttpURLConnection: No data in the POST request

I have created a Django Rest server. And I am trying to POST a JSON content in java using HttpURLConnection. However, when I am registering OutputStream in java, the server get a POST request with no JSON content. Hence the server rejecting the request with HTTP response code 400. I did write JSON data just after registering OutputSream. May be POST has been made before writing to OutputStream. The following is the code in JAVA.
public static void post(HttpURLConnection urlConnection1)
throws IOException, InterruptedException {
// urlConnection.setRequestMethod("POST");
URL url = new URL("http://127.0.0.1:8000/message/");
byte[] authStr=Base64.encodeBase64("sp:password".getBytes());
String enc=new String(authStr);
HttpURLConnection urlConnection = (HttpURLConnection) url
.openConnection();
urlConnection.setRequestProperty("Authorization", "Basic "+ enc);
try {
urlConnection.setDoOutput(true);
urlConnection.setChunkedStreamingMode(0);
urlConnection
.setRequestProperty("Content-Type", "application/json");
urlConnection.setRequestMethod("POST");
urlConnection.setInstanceFollowRedirects(false);
OutputStream out = urlConnection.getOutputStream();
//Thread.sleep(5000);
writeStream(out);
out.flush();
InputStream in = urlConnection.getInputStream();
readStream(in);
} finally {
urlConnection.disconnect();
}
}
private static void writeStream(OutputStream out) {
// TODO Auto-generated method stub
try {
JSONObject grp = new JSONObject();
JSONObject gp = new JSONObject();
gp.put("id", "g3bj25");
gp.put("from", "someone");
out.write(gp.toString().getBytes());
System.out.println(gp.toString());
} catch (IOException | JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Do I have to make any changes in server side so that it waits for content?
The problem is, that your URL is not complete, the name of the script is missing.
URL url = new URL("http://127.0.0.1:8000/message/");
supposes that you are calling http://127.0.0.1/message/index.php but here you're not allowed to let the index.php (or whatever) implicit.
The script gets called, but the POST data is not sent, or it is truncated by the Webserver when handling the request. I had the same problem and spent hours until I found the reason. Then I did not dig further to find out exactly where the POST data gets dropped.

Posting to a webservice using httpurlconnection

How come I am only allowed to make posts to .com url's but not .asmx url's? Im a bit confused as what I want to generally do is send xml content to a .asmx url web service eventually. Can anyone supply me with tips why this doesn't work, and how I can post to a .asmx file?
public class POSTSenderExample {
public String echoCuties(String query) throws IOException {
// Encode the query
String encodedQuery = URLEncoder.encode(query, "UTF-8");
// This is the data that is going to be send to itcuties.com via POST request
// 'e' parameter contains data to echo
String postData = "e=" + encodedQuery;
URL url = new URL("http://echo.itgeeeks.asmx");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
connection.setRequestProperty("Content-Length", String.valueOf(postData.length()));
// Write data
OutputStream os = connection.getOutputStream();
os.write(postData.getBytes());
// Read response
StringBuilder responseSB = new StringBuilder();
BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line;
while ( (line = br.readLine()) != null)
responseSB.append(line);
// Close streams
br.close();
os.close();
return responseSB.toString();
}
// Run this example
public static void main(String[] args) {
try {
System.out.println(new POSTSenderExample().echoCuties("Hi there!"));
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
Using "POST" is correct.
Instead of calling
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
you have to call
connection.setRequestProperty("Content-Type", "text/xml; charset=utf-8");
(if you are using utf-8 encoding which is probably the case).
You also have to set the SOAP Action in the http- Header:
connection.setRequestProperty("SOAPAction", SOAPAction);
You can find the SOAP Action eihter in the wsdl- file. What I did to find out all expected Parameters: I used a working WS Client, and traced the TCP traffic in order to find out the expected HTTP headers.

Android Java HttpUrlConnection freezing

I suspect I'm running into some issues borne out of threading in my simple Android app.
I have a Activity which does the following:
runs a dialog on main thread
spins a background thread and hits a PHP script for retreiving data using DefaultHttpClient and close this connection. This successfully returns a URL to a picture on the internet
open HttpUrlConnection called conn and try conn.connect
app freezes at this point with no error
Not sure what code to put here, I could paste it all but that would be too much so let me know if any more info is needed:
/**
* Background Async Task to Load all Question by making HTTP Request
*/
class LoadAllImages extends AsyncTask<String, String, String> {
/**
* Before starting background thread Show Progress Dialog
* */
#Override
protected void onPreExecute() {
super.onPreExecute();
// dialog init'd here
}
#Override
protected String doInBackground(String... args) {
// Building Parameters
List<NameValuePair> params = new ArrayList<NameValuePair>();
// getting JSON string from URL
JSONObject json = jParser.makeHttpRequest(url_question_details, "GET", params);
// Check your log cat for JSON response
Log.d("All Questions: ", json.toString());
try {
// images found
// Getting Array of questions
images = json.getJSONArray(TAG_IMAGES);
// looping through All questions
for (int i = 0; i < images.length(); i++) {
JSONObject c = images.getJSONObject(i);
// Storing each json item in variable
String id = c.getString(TAG_IMAGEID);
String location = c.getString(TAG_IMAGELOCATION);
URL myFileUrl = null;
try {
myFileUrl = new URL(location);
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
HttpURLConnection conn = (HttpURLConnection) myFileUrl.openConnection();
conn.setDoInput(true);
conn.connect(); // freezes here
int length = conn.getContentLength();
int[] bitmapData = new int[length];
byte[] bitmapData2 = new byte[length];
InputStream is = conn.getInputStream();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
First of all make sure you added Internet Permission to manifest:
<uses-permission android:name="android.permission.INTERNET" />
outside the application tag in your AndroidManifest.xml
Troubleshooting:
Try access the same URL using your browser
Check if you are not behind proxy or server is not behind proxy
Try pinging the server see and check the latency.
Try catching all exceptions:
Change } catch (IOException e) { to } catch (Exception e) {
If all looks good try this code:
System.setProperty("http.keepAlive", "false");
HttpURLConnection conn = (HttpURLConnection) myFileUrl.openConnection();
conn.setUseCaches(false);
conn.setConnectTimeout(30000);
conn.setDoOutput(true);
conn.setDoInput(true);
//conn.connect(); // You are allready connected after openConnection().
If still no luck, try using HttpClient & HttpGet this way:
final HttpClient client = new DefaultHttpClient();
final HttpGet conn = new HttpGet(myFileUrl.toString());
HttpResponse response = client.execute(conn);
InputStream is = response.getEntity().getContent();
I'd at least put both connect and read timeout in, e.g.
conn.setConnectTimeout(5000);
conn.setReadTimeout(5000);
I had the exact same issue that drove me crazy to solve. I was already setting the timout params, but the httpurlconnection was hanging on connect() call, or later on getInputStream() if I don't call explicitly connect().
Using a raw thread instead of the asynctask worked for me, without changing anything else...
new Thread(() -> task.doInBackground())
More a workaround than a solution, but better than nothing.
Remove these 2 lines:
conn.setDoInput(true);
conn.connect(); // freezes here
When you do this:
HttpURLConnection conn = (HttpURLConnection) myFileUrl.openConnection();
int length = conn.getContentLength();
You are already connected. Calling conn.getContentLength() causes HttpURLConnection to make the connection, sends the request and fetches the response. You don't need to explicitly connect. You also don't need to call setDoInput(true) since that is the default setting.

Categories