1

I've read lots and tried lots relating to HTTP POSTS using HttpURLConnection and almost everything I come across has a similar structure which starts with these 3 lines:

  url = new URL(targetURL);
  connection = (HttpURLConnection)url.openConnection();
  connection.setRequestMethod("POST");

When I try this I always get a "Connection Already Established" exception when calling setRequestMethod, which makes perfect sense as I'm clearly calling openConnection before setting the request type. Although reading the docs openConnection doesn't actually open the connection in theory.

There are several posts about this problem on SO such as this and this. I don't understand however why every piece of advice about how to write this code has these 3 lines in this order.

I'm guessing this code must work in most instances as someone must have tested it, so why doesn't this code work for me? How should I be writing this code?

I am aware these are other libraries I can use out there, I'm just wondering why this doesn't work.

Community
  • 1
  • 1
Will Calderwood
  • 3,878
  • 2
  • 31
  • 55
  • @scrappedcola I've read that. The question is why doesn't this code work for me, and how should I be writing this code? How do I create the connection without a call to openConnection? And if this is wrong, why is it what everyone advises? – Will Calderwood Nov 14 '14 at 23:24
  • @scrappedcola I've read the docs. How do I create the connection without a call to openConnection? – Will Calderwood Nov 14 '14 at 23:43
  • @scrappedcola One more point is that the docs state: "It should be noted that a URLConnection instance does not establish the actual network connection on creation. This will happen only when calling URLConnection.connect()." So openConnection does not actually connect. – Will Calderwood Nov 15 '14 at 07:18
  • There's no other order in which these three lines can possibly appear. That's why they always appear in this order. There's no reason why the request method can't be set after the connection is established, as long as the request hasn't been sent yet. I have all kinds of working code that does this. Is this your real code? – user207421 Nov 15 '14 at 08:44
  • @EJP That's one of the many bits of real code I've tried. – Will Calderwood Nov 15 '14 at 11:48
  • Where's the rest of it? – user207421 Nov 15 '14 at 21:24
  • @EJP Replacing connection.setDoOutput(true) with connection.setRequestMethod("POST") in my code in the answer I posted triggers the exception. – Will Calderwood Nov 15 '14 at 22:05
  • 1
    @scrappedcola The 'first post', or rather the accepted answer to it, is nonsense. You can't possibly call `HttpURLConnection.setRequestMethod()` before you have an `HttpURLConnection`. – user207421 Nov 16 '14 at 09:06

2 Answers2

1

Why the suspect code in the question has been duplicated all over the internet is something I can't answer. Nor can I answer why it seems to work for some people and not others. I can however answer the other question now, mainly thanks to this link that Luiggi pointed me to.

The key here is understanding the intricacies of the HttpURLConnection class. When first created the class defaults to a "GET" request method, so nothing needs to be changed in this instance. The following is rather unintuitive, but to set the request method to "POST" you should not call setRequestMethod("POST"), but rather setDoOutput(true) which implicitly sets the request method to post. Once you've done that you're good to go.

Below, I believe, is what a post method should look like. This is for posting json, but can obviously be altered for any other content type.

public static String doPostSync(final String urlToRead, final String content) throws IOException {
    final String charset = "UTF-8";
    // Create the connection
    HttpURLConnection connection = (HttpURLConnection) new URL(urlToRead).openConnection();
    // setDoOutput(true) implicitly set's the request type to POST
    connection.setDoOutput(true);
    connection.setRequestProperty("Accept-Charset", charset);
    connection.setRequestProperty("Content-type", "application/json");

    // Write to the connection
    OutputStream output = connection.getOutputStream();
    output.write(content.getBytes(charset));
    output.close();

    // Check the error stream first, if this is null then there have been no issues with the request
    InputStream inputStream = connection.getErrorStream();
    if (inputStream == null)
        inputStream = connection.getInputStream();

    // Read everything from our stream
    BufferedReader responseReader = new BufferedReader(new InputStreamReader(inputStream, charset));

    String inputLine;
    StringBuffer response = new StringBuffer();

    while ((inputLine = responseReader.readLine()) != null) {
        response.append(inputLine);
    }
    responseReader.close();

    return response.toString();
}
Community
  • 1
  • 1
Will Calderwood
  • 3,878
  • 2
  • 31
  • 55
0

As per https://stackoverflow.com/a/3324964/436524, you need to call connection.setDoOutput(true) for it to expect a POST request.

This makes your code like this:

  url = new URL(targetURL);
  connection = (HttpURLConnection)url.openConnection();
  connection.setDoOutput(true);
Community
  • 1
  • 1
Octavia Togami
  • 3,638
  • 4
  • 29
  • 42
  • I still get the same exception calling setDoOutput(true) first. – Will Calderwood Nov 14 '14 at 23:36
  • @LuiggiMendoza Thanks for the interesting link. That states that calling setDoOutput(true) implicitly sets the request type to POST so there's no need to call setRequestMethod. I don't understand how the same incorrect code can be duplicated in so many places. – Will Calderwood Nov 14 '14 at 23:44
  • `setDoOutput(true)` implies `setRequestMethod("POST")`. There's no need to call them both. – user207421 Nov 15 '14 at 09:46