Así que estoy tratando de enviar una solicitud POST multipart/form-data con archivo de imagen grande. No puedo convertir previamente la matriz de bytes a archivos, mi aplicación se bloqueará con la excepción OutOfMemory, así que tengo que escribir el contenido del archivo directamente en la salida de la conexión. Además, mi servidor no es compatible con el modo fragmentado, por lo que tengo que calcular la longitud del contenido antes de enviar datos y usar setFixedLengthStreamingMode de la conexión.HTTPURLConnection - POST multipart/form-data con archivo grande con FixedLengthStreamingMode
public void createImagePostWithToken(String accessToken, String text,
String type, String imagePath) {
URL imageUrl = null;
String lineEnd = "\r\n";
String twoHyphens = "--";
// generating byte[] boundary here
HttpURLConnection conn = null;
DataOutputStream outputStream = null;
DataInputStream inputStream = null;
int bytesRead, bytesAvailable, bufferSize;
byte[] buffer;
int maxBufferSize = 1*1024*1024;
try
{
long contentLength;
int serverResponseCode;
String serverResponseMessage;
File file = new File(imagePath);
FileInputStream fileInputStream = new FileInputStream(file);
imageUrl = buildUri("posts").toURL();
conn = (HttpURLConnection)imageUrl.openConnection();
conn.setConnectTimeout(30000);
conn.setReadTimeout(30000);
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);
String stringForLength = new String();
stringForLength += "Content-Type: multipart/form-data;boundary=" + boundary;
stringForLength += twoHyphens + boundary + lineEnd + "Content-Disposition: form-data; name=\"access_token\"" + lineEnd;
stringForLength += "Content-Type: text/plain;charset=UTF-8" + lineEnd + "Content-Length: " + accessToken.length() + lineEnd + lineEnd;
stringForLength += accessToken + lineEnd + twoHyphens + boundary + lineEnd;
stringForLength += "Content-Disposition: form-data; name=\"text\"" + lineEnd;
stringForLength += "Content-Type: text/plain;charset=UTF-8" + lineEnd + "Content-Length: " + text.length() + lineEnd + lineEnd;
stringForLength += text + lineEnd + twoHyphens + boundary + lineEnd;
stringForLength += "Content-Disposition: form-data; name=\"type\"" + lineEnd;
stringForLength += "Content-Type: text/plain;charset=UTF-8" + lineEnd + "Content-Length: " + type.length() + lineEnd + lineEnd;
stringForLength += type + lineEnd + twoHyphens + boundary + lineEnd;
stringForLength += twoHyphens + boundary + lineEnd + "Content-Disposition: form-data; name=\"image\"" + lineEnd;
stringForLength += "Content-Type: application/octet-stream" + lineEnd + "Content-Length: " + file.length() + lineEnd + lineEnd;
stringForLength += lineEnd + twoHyphens + boundary + twoHyphens + lineEnd;
int totalLength = stringForLength.length() + (int)file.length();
conn.setFixedLengthStreamingMode(totalLength);
outputStream = new DataOutputStream(conn.getOutputStream());
outputStream.writeBytes(twoHyphens + boundary + lineEnd);
// access token
outputStream.writeBytes("Content-Disposition: form-data; name=\"access_token\"" + lineEnd);
outputStream.writeBytes("Content-Type: text/plain;charset=UTF-8" + lineEnd);
outputStream.writeBytes("Content-Length: " + accessToken.length() + lineEnd);
outputStream.writeBytes(lineEnd);
outputStream.writeBytes(accessToken + lineEnd);
outputStream.writeBytes(twoHyphens + boundary + lineEnd);
// text
outputStream.writeBytes("Content-Disposition: form-data; name=\"text\"" + lineEnd);
outputStream.writeBytes("Content-Type: text/plain;charset=UTF-8" + lineEnd);
outputStream.writeBytes("Content-Length: " + text.length() + lineEnd);
outputStream.writeBytes(lineEnd);
outputStream.writeBytes(text + lineEnd);
outputStream.writeBytes(twoHyphens + boundary + lineEnd);
// type
outputStream.writeBytes("Content-Disposition: form-data; name=\"type\"" + lineEnd);
outputStream.writeBytes("Content-Type: text/plain;charset=UTF-8" + lineEnd);
outputStream.writeBytes("Content-Length: " + type.length() + lineEnd);
outputStream.writeBytes(lineEnd);
outputStream.writeBytes(type + lineEnd);
outputStream.writeBytes(twoHyphens + boundary + lineEnd);
// image
outputStream.writeBytes(twoHyphens + boundary + lineEnd);
outputStream.writeBytes("Content-Disposition: form-data; name=\"image\"" + lineEnd);
//outputStream.writeBytes(lineEnd);
outputStream.writeBytes("Content-Type: application/octet-stream" + lineEnd);
outputStream.writeBytes("Content-Length: " + file.length() + lineEnd);
outputStream.writeBytes(lineEnd);
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
buffer = new byte[bufferSize];
// Read file
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
while (bytesRead > 0)
{
outputStream.write(buffer, 0, bufferSize);
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
}
outputStream.writeBytes(lineEnd);
outputStream.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
Log.d("posttemplate", "connection outputstream size is " + outputStream.size());
// finished with POST request body
// Responses from the server (code and message)
serverResponseCode = conn.getResponseCode();
serverResponseMessage = conn.getResponseMessage();
Log.d("posttemplate", "server response code "+ serverResponseCode);
Log.d("posttemplate", "server response message "+ serverResponseMessage);
fileInputStream.close();
conn.disconnect();
outputStream.flush();
outputStream.close();
} catch (MalformedURLException e)
{
Log.d("posttemplate", "malformed url", e);
//TODO: catch exception;
} catch (IOException e)
{
Log.d("posttemplate", "ioexception", e);
//TODO: catch exception
}
}
Por desgracia, mis aplicación se bloquea con IOException en outputStream.close(), y no tengo ni idea de por qué:
03-16 13:56:51.035: D/posttemplate(6479): java.io.IOException: unexpected end of stream
03-16 13:56:51.035: D/posttemplate(6479): at org.apache.harmony.luni.internal.net.www.protocol.http.FixedLengthOutputStream.close(FixedLengthOutputStream.java:57)
03-16 13:56:51.035: D/posttemplate(6479): at java.io.FilterOutputStream.close(FilterOutputStream.java:66)
03-16 13:56:51.035: D/posttemplate(6479): at com.futubra.api.impl.PostTemplate.createImagePostWithToken(PostTemplate.java:282)
03-16 13:56:51.035: D/posttemplate(6479): at com.futubra.FutubraNewPostActivity.createPost(FutubraNewPostActivity.java:128)
03-16 13:56:51.035: D/posttemplate(6479): at com.futubra.FutubraNewPostActivity_.access$2(FutubraNewPostActivity_.java:1)
03-16 13:56:51.035: D/posttemplate(6479): at com.futubra.FutubraNewPostActivity_$5.run(FutubraNewPostActivity_.java:141)
03-16 13:56:51.035: D/posttemplate(6479): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1088)
03-16 13:56:51.035: D/posttemplate(6479): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:581)
03-16 13:56:51.035: D/posttemplate(6479): at java.lang.Thread.run(Thread.java:1019)
¿Me podría apuntar a este error que mencionas? Parece que me estoy encontrando con el mismo problema usando HttpsUrlConnection en Gingerbread. – HungryTux