Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why are there streams in the HttpURLConnection API?

From what I understand about HTTP, it works like this: The client assembles a message, consisting of some header fields and (possibly) a body and sends it to the server. The server processes it, assembles its own response message and sends it back to the client.

And so I come to the question:

Why are there all of a sudden streams in HttpURLConnection?

This makes no sense to me. It makes it look like there is a continuous open channel. At what point does the message actually get sent to the server? On connect? On getInputStream? When trying to read from the stream? What if I have payload, does it get sent at a different time then? Can I do write-read-write-read with just a single connection?

I'm sure I just haven't understood it right yet, but right now it just seems like a bad API to me.

I would have more expected to see something like this:

HttpURLConnection http = url.openConnection();
HttpMessage req = new HttpMessage;
req.addHeader(...);
req.setBody(...);
http.post(req);

// Block until response is available (Future pattern)
HttpMessage res = http.getResponse();
like image 885
BadIdeaException Avatar asked Feb 14 '23 13:02

BadIdeaException


1 Answers

IMHO HttpURLConnection has indeed a bad API. But handling the input and output message as streams is a way to deal efficiently with large amounts of data. I think all other answers (at this moment 5!) are correct. There are some questions open:

At what point does the message actually get sent to the server? On connect? On getInputStream? When trying to read from the stream?

There are some triggers when all collected data (e.g. headers, options for timeout, ...) is actually transmitted to the server. In most cases you don't have to call connect, this is done implicitly e.g. when calling getResponseCode() or getInputStream(). (BTW I recommend to call getResponseCode() before getInputStream() because if you get an error code (e.g. 404), getInputStream will throw an Exception and you should better call getErrorStream().)

What if I have payload, does it get sent at a different time then?

You have to call getOutputStream() and then send the payload. This should be done (obviously) after you added the headers. After closing the stream you can expect a response from the server.

Can I do write-read-write-read with just a single connection?

No. Technically this would be possible when using keep-alive. But HttpURLConnection handles this under the cover and you can only do one request-response roundtrip with an instance of this class.

Making life easier

If you don't want to fight with the horrible API of HttpURLConnection, you could have a look at some abstraction APIs listed on DavidWebb. When using DavidWebb, a typical request looks like this:

Webb webb = Webb.create();
String result = webb.post("http://my-server/path/resource")
    .header("auth-token", myAuthToken)
    .body(myBody)
    .ensureSuccess()
    .asString()
    .getBody();
like image 92
hgoebl Avatar answered Feb 16 '23 02:02

hgoebl