15

I'm trying to make a Request to a WebService from an android application, using HttpUrlConnection. But sometimes it works, and sometimes it does not.

When I try sending this value:

JSON value

 {"Calle":"Calle Pérez 105","DetalleDireccion":"","HoraPartida":"May 18, 2014 9:17:10 AM","Numero":0,"PuntoPartidaLat":18.477295994621315,"PuntoPartidaLon":-69.93638522922993,"Sector":"Main Sector"}

I got an "unexpected end of stream" Exception in the DataOutputStream close function.

Here is my code:

DataOutputStream printout;
// String json;
byte[] bytes;
DataInputStream input;

URL serverUrl = null;
try {
    serverUrl = new URL(Config.APP_SERVER_URL + URL);
} catch (MalformedURLException e) {
    ...
} 

bytes = json.getBytes();
try {

    httpCon = (HttpURLConnection) serverUrl.openConnection();
    httpCon.setDoOutput(true);
    httpCon.setUseCaches(false);
    httpCon.setFixedLengthStreamingMode(bytes.length);
    httpCon.setRequestProperty("Authorization", tokenType + " "+ accessToken);
    httpCon.setRequestMethod("POST");
    httpCon.setRequestProperty("Content-Type", "application/json");

    printout = new DataOutputStream(httpCon.getOutputStream());
    printout.writeBytes(json);
    printout.flush();
    printout.close();
    ...
}
Laggel
  • 1,356
  • 3
  • 19
  • 36
  • It might not relate to your problem: You don't want to use a *DataOutputStream* instance. This is a binary, rather proprietary format. The correct way is to convert the JSON string into a byte array using the UTF-8 encoding and then write it directly to the connection's output stream. – Codo May 18 '14 at 15:00
  • A further problem in your code is that you convert the JSON string to a byte array using a default encoding. You then use the length of the array to set the content length. However, you apply the *DataOutputStream* in a way where the string is written in ASCII mode (writeBytes doesn't use an encoding; it discards the high bits). So you might have mismatch between the announced and the effective content length. – Codo May 18 '14 at 15:03

2 Answers2

11

Here's a solution with the following changes:

  • It gets rid of the DataOutputStream, which is certainly the wrong thing to use.
  • It correctly sets and delivers the content length.
  • It doesn't depend on any defaults regarding the encoding, but explicitly sets UTF-8 in two places.

Try it:

// String json;

URL serverUrl = null;
try {
    serverUrl = new URL(Config.APP_SERVER_URL + URL);
} catch (MalformedURLException e) {
    ...
} 

try {
    byte[] bytes = json.getBytes("UTF-8");

    httpCon = (HttpURLConnection) serverUrl.openConnection();
    httpCon.setDoOutput(true);
    httpCon.setUseCaches(false);
    httpCon.setFixedLengthStreamingMode(bytes.length);
    httpCon.setRequestProperty("Authorization", tokenType + " "+ accessToken);
    httpCon.setRequestMethod("POST");
    httpCon.setRequestProperty("Content-Type", "application/json; charset=UTF-8");

    OutputStream os = httpCon.getOutputStream();
    os.write(bytes);
    os.close();

    ...
}
Codo
  • 75,595
  • 17
  • 168
  • 206
  • I literally love you, the problem was happening when the string included accented characters like 'í' but with your approach works like a charm. – Laggel May 18 '14 at 15:44
  • 1
    @Laggel: could that be due to encoding problems? For example if a multibyte encoding such as UTF-8 is used then accented characters will typically ytake up more than 1 byte, and then the length of the bytes vs number of characters does not match any more. – Mr. Developerdude Nov 23 '14 at 14:40
  • 1
    Yes, that's why the length needs to be taken after encoding it as UTF-8. – Codo Nov 24 '14 at 07:13
  • Also for anybody else, you can't have `setChunkedStreamingMode(0)` set, or it won't work right. – user3413723 Feb 11 '23 at 00:41
1

From the oracle documentation here. We know that flush method of DataOutputStream calls the flush method of the underlying output stream. If you look at the URLConnection class in here it says that every subclass of URLConnection must have this method overridden. If you see the HttpUrlConnection here we see that flush method is not overridden. It could be one of the reasons for your problem.

working
  • 873
  • 3
  • 11
  • 21