I'm trying to make a POST call using HttpUrlConnection but with no success. I'm getting 'IllegalStateException: already connected' error message frequently. I'm not interested in reusing the connection. Please check my code and tell me if I'm doing anything wrong:
public static final int CONNECTION_TIME_OUT = 10000;
public SimpleResponse callPost(String urlTo, Map<String, String> params) {
System.setProperty("http.keepAlive", "false");
HttpURLConnection conn = null;
SimpleResponse response = new SimpleResponse(0, null);
try {
URL url = new URL(urlTo);
conn = (HttpURLConnection) url.openConnection();
conn.setUseCaches(false);
conn.setAllowUserInteraction(false);
conn.setConnectTimeout(CONNECTION_TIME_OUT);
conn.setReadTimeout(CONNECTION_TIME_OUT);
conn.setInstanceFollowRedirects(false);
conn.setRequestMethod("POST");
conn.setRequestProperty("Connection", "close");
conn.setRequestProperty("Content-type", "application/x-www-form-urlencoded");
conn.setRequestProperty("Content-Length", String.valueOf(postDataBytes.length));
conn.setDoOutput(true);
OutputStream os = conn.getOutputStream();
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os, "UTF-8"));
writer.write(paramsToString(params));
writer.flush();
writer.close();
os.close();
int responseCode = conn.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
InputStream in = conn.getInputStream();
String result = StringUtils.fromInputStream(in);
response = new SimpleResponse(responseCode, result);
in.close();
} else {
response = new SimpleResponse(responseCode, null);
}
} catch (Exception e) {
e.printStackTrace();
}
if (conn != null) {
conn.disconnect();
}
return response;
}
private String paramsToString(Map<String, String> params) {
if (params == null || params.isEmpty()) {
return "";
}
Uri.Builder builder = new Uri.Builder();
for (Map.Entry<String, String> entry : params.entrySet()) {
builder.appendQueryParameter(entry.getKey(), entry.getValue());
}
return builder.build().getEncodedQuery();
}
Update:
Works sometimes, and sometimes doesn't!
Works on some projects, on others doesn't!
The same exact code, and each time the same exception: Already connected
Why I'm not able to get a new fresh connection each time?
I think your problem is this:
conn.setRequestProperty("Content-Length", String.valueOf(postDataBytes.length));
I can't see where postDataBytes
is declared, but since you're processing the parameters in paramsToString
, my guess is that they have no relationship.
Now, I'm not an expert on RFC 2616 (HTTP), but what I think is happening is that the length of postDataBytes
is larger than your request size, so the server is not disconnecting the socket on its end. Those URLConnection
objects are pooled, so when you go to get a connection object, its values have been cleaned up for reuse, but the actual connection is still open.
Here's some code I think you should try. If it doesn't fix your problem, I don't get rep bonus, but it's still definitely more correct than what you have:
private static final String CHARSET = "ISO-8859-1"; // or try "UTF-8"
public SimpleResponse callPost(String urlTo, Map<String, String> params) {
// get rid of this...
// System.setProperty("http.keepAlive", "false");
HttpURLConnection conn = null;
SimpleResponse response = new SimpleResponse(0, null);
try {
URL url = new URL(urlTo);
conn = (HttpURLConnection) url.openConnection();
conn.setUseCaches(false);
conn.setAllowUserInteraction(false);
conn.setConnectTimeout(CONNECTION_TIME_OUT);
conn.setReadTimeout(CONNECTION_TIME_OUT);
conn.setInstanceFollowRedirects(false);
conn.setRequestMethod("POST");
// ... and get rid of this
// conn.setRequestProperty("Connection", "close");
conn.setRequestProperty("Content-type", "application/x-www-form-urlencoded; charset=" + CHARSET);
String content = paramsToString(params);
int length = content.getBytes(Charset.forName(CHARSET)).length;
conn.setRequestProperty("Content-Length", Integer.toString(length));
conn.setDoOutput(true);
OutputStream os = conn.getOutputStream();
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os, CHARSET));
writer.write(content);
writer.flush();
writer.close();
os.close();
int responseCode = conn.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
InputStream in = conn.getInputStream();
String result = StringUtils.fromInputStream(in);
response = new SimpleResponse(responseCode, result);
in.close();
} else {
response = new SimpleResponse(responseCode, null);
}
} catch (Exception e) {
e.printStackTrace();
}
if (conn != null) {
conn.disconnect();
}
return response;
}
I apologize for any compile errors. I'm useless without an IDE. I proofed it the best I could.
I used the Latin-1 encoding. If that doesn't do it for you, you can try UTF-8.
Another thing you can try is giving up on the content length altogether and calling
conn.setChunkedStreamingMode(0);
And yes, I realize that the getBytes()
call and OutputStreamWriter
are duplicating the same process. You can work on that once you get this problem fixed.
I cannot seem to figure out why you get an "Already connected error" but here's the code I use to make POST requests. I close the input/output streams and the connection after sending the request , that may help you (though i'm not sure exactly)
try {
URL url = new URL(stringURL);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json;charset=UTF-8");
connection.setRequestProperty("Accept","application/json");
//connection.setRequestProperty("Content-Length", Integer.toString(urlParameters.getBytes().length));
//connection.setRequestProperty("Connection", "Keep-Alive");
connection.setReadTimeout(10*1000);
connection.setUseCaches(false);
connection.setDoInput(true);
connection.setDoOutput(true);
//Request
DataOutputStream wr = new DataOutputStream(connection.getOutputStream());
wr.writeBytes(params[1]);
wr.flush();
wr.close();
//Response
InputStream is = connection.getInputStream();
BufferedReader rd = new BufferedReader(new InputStreamReader(is));
String line;
response = new StringBuffer();
//Expecting answer of type JSON single line {"json_items":[{"status":"OK","message":"<Message>"}]}
while ((line = rd.readLine()) != null) {
response.append(line);
}
rd.close();
System.out.println(response.toString()+"\n");
connection.disconnect(); // close the connection after usage
} catch (Exception e){
System.out.println(this.getClass().getSimpleName() + " ERROR - Request failed");
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With