HttpURLConnection的 - POST的multipart / form-data的大文件FixedLengthStreamingMode [英] HTTPURLConnection - POST multipart/form-data with large file with FixedLengthStreamingMode
问题描述
所以我想送与大的图像文件的multipart / form-data发布请求。我不能pre-转换文件的字节数组,我的应用程序将与内存不足的异常崩溃,所以我必须写文件内容直接连接的输出流。另外,我的服务器不支持分块模式,所以我必须要计算的内容长度发送数据前,使用连接的setFixedLengthStreamingMode。
公共无效createImagePostWithToken(字符串accessToken,字符串文字,
字符串类型,字符串的ImagePath){
URL IMAGEURL = NULL;
字符串lineEnd =\ r \ N的;
串twoHyphens = - ;
//生成byte []的边界在这里
HttpURLConnection的康恩= NULL;
DataOutputStream类的OutputStream = NULL;
的DataInputStream的InputStream = NULL;
INT读取动作,方bytesAvailable,缓冲区大小;
byte []的缓冲区;
INT maxBufferSize = 1 * 1024 * 1024;
尝试
{
长CONTENTLENGTH;
INT serverResponse code;
字符串serverResponseMessage;
档案文件=新的文件(的ImagePath);
的FileInputStream的FileInputStream =新的FileInputStream(文件);
IMAGEURL = buildUri(上岗)的toURL()。
康恩=(HttpURLConnection类)imageUrl.openConnection();
conn.setConnectTimeout(30000);
conn.setReadTimeout(30000);
conn.setDoOutput(真正的);
conn.setDoInput(真正的);
conn.setRequestMethod(POST);
conn.setRequestProperty(内容类型,多部分/格式数据;边界=+界);
字符串stringForLength =新的String();
stringForLength + =内容类型:多部分/格式数据;边界=+边界;
stringForLength + = twoHyphens +边界+ lineEnd +内容处置:表格数据;名称= \access_token \+ lineEnd;
stringForLength + =内容类型:text / plain的;字符集= UTF-8+ lineEnd +的Content-Length:+ accessToken.length()+ lineEnd + lineEnd;
stringForLength + = accessToken + lineEnd + twoHyphens +边界+ lineEnd;
stringForLength + =内容处置:表格数据;名称= \文本\+ lineEnd;
stringForLength + =内容类型:text / plain的;字符集= UTF-8+ lineEnd +的Content-Length:+ text.length()+ lineEnd + lineEnd;
stringForLength + =文字+ lineEnd + twoHyphens +边界+ lineEnd;
stringForLength + =内容处置:表格数据;名称= \类型\+ lineEnd;
stringForLength + =内容类型:text / plain的;字符集= UTF-8+ lineEnd +的Content-Length:+ type.length()+ lineEnd + lineEnd;
stringForLength + =型+ lineEnd + twoHyphens +边界+ lineEnd;
stringForLength + = twoHyphens +边界+ lineEnd +内容处置:表格数据;名称= \图像\+ lineEnd;
stringForLength + =内容类型:应用程序/八位字节流+ lineEnd +的Content-Length:+ file.length()+ lineEnd + lineEnd;
stringForLength + = lineEnd + twoHyphens +边界+ twoHyphens + lineEnd;
INT totalLength = stringForLength.length()+(int)的file.length();
conn.setFixedLengthStreamingMode(totalLength);
的OutputStream =新DataOutputStream类(conn.getOutputStream());
outputStream.writeBytes(twoHyphens +边界+ lineEnd);
// 访问令牌
outputStream.writeBytes(内容处置:表格数据;名称= \access_token \+ lineEnd);
outputStream.writeBytes(内容类型:text / plain的;字符集= UTF-8+ lineEnd);
outputStream.writeBytes(内容长度:+ accessToken.length()+ lineEnd);
outputStream.writeBytes(lineEnd);
outputStream.writeBytes(accessToken + lineEnd);
outputStream.writeBytes(twoHyphens +边界+ lineEnd);
// 文本
outputStream.writeBytes(内容处置:表格数据;名称= \文本\+ lineEnd);
outputStream.writeBytes(内容类型:text / plain的;字符集= UTF-8+ lineEnd);
outputStream.writeBytes(内容长度:+ text.length()+ lineEnd);
outputStream.writeBytes(lineEnd);
outputStream.writeBytes(文字+ lineEnd);
outputStream.writeBytes(twoHyphens +边界+ lineEnd);
// 类型
outputStream.writeBytes(内容处置:表格数据;名称= \类型\+ lineEnd);
outputStream.writeBytes(内容类型:text / plain的;字符集= UTF-8+ lineEnd);
outputStream.writeBytes(内容长度:+ type.length()+ lineEnd);
outputStream.writeBytes(lineEnd);
outputStream.writeBytes(类型+ lineEnd);
outputStream.writeBytes(twoHyphens +边界+ lineEnd);
// 图像
outputStream.writeBytes(twoHyphens +边界+ lineEnd);
outputStream.writeBytes(内容处置:表格数据;名称= \图像\+ lineEnd);
//outputStream.writeBytes(lineEnd);
outputStream.writeBytes(内容类型:应用程序/八位字节流+ lineEnd);
outputStream.writeBytes(内容长度:+ file.length()+ lineEnd);
outputStream.writeBytes(lineEnd);
方bytesAvailable = fileInputStream.available();
BUFFERSIZE = Math.min(方bytesAvailable,maxBufferSize);
缓冲区=新的字节[BUFFERSIZE]
//读取文件
读取动作= fileInputStream.read(缓冲液,0,BUFFERSIZE);
而(读取动作大于0)
{
outputStream.write(缓冲液,0,BUFFERSIZE);
方bytesAvailable = fileInputStream.available();
BUFFERSIZE = Math.min(方bytesAvailable,maxBufferSize);
读取动作= fileInputStream.read(缓冲液,0,BUFFERSIZE);
}
outputStream.writeBytes(lineEnd);
outputStream.writeBytes(twoHyphens +边界+ twoHyphens + lineEnd);
Log.d(posttemplate,连接的OutputStream大小为+ outputStream.size());
//使用POST请求主体完成
从服务器//回应(code和消息)
serverResponse code = conn.getResponse code();
serverResponseMessage = conn.getResponseMessage();
Log.d(posttemplate,服务器响应code+ serverResponse code);
Log.d(posttemplate,服务器响应消息+ serverResponseMessage);
fileInputStream.close();
conn.disconnect();
outputStream.flush();
outputStream.close();
}赶上(MalformedURLException的E)
{
Log.d(posttemplate,错误的URL,E);
// TODO:catch异常;
}赶上(IOException异常E)
{
Log.d(posttemplate,IOException异常,E);
// TODO:catch异常
}
}
不幸的是,我的应用程序崩溃,IOException异常在outputStream.close(),我不知道为什么:
03-16 13:56:51.035:D / posttemplate(6479):java.io.IOException异常:流意外结束
03-16 13:56:51.035:D / posttemplate(6479):在org.apache.harmony.luni.internal.net.www.protocol.http.FixedLengthOutputStream.close(FixedLengthOutputStream.java:57)
03-16 13:56:51.035:D / posttemplate(6479):在java.io.FilterOutputStream.close(FilterOutputStream.java:66)
03-16 13:56:51.035:D / posttemplate(6479):在com.futubra.api.impl.PostTemplate.createImagePostWithToken(PostTemplate.java:282)
03-16 13:56:51.035:D / posttemplate(6479):在com.futubra.FutubraNewPostActivity.createPost(FutubraNewPostActivity.java:128)
03-16 13:56:51.035:D / posttemplate(6479):在com.futubra.FutubraNewPostActivity_.access $ 2(FutubraNewPostActivity_.java:1)
03-16 13:56:51.035:D / posttemplate(6479):在com.futubra.FutubraNewPostActivity_ $ 5.run(FutubraNewPostActivity_.java:141)
03-16 13:56:51.035:D / posttemplate(6479):在java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1088)
03-16 13:56:51.035:D / posttemplate(6479):在java.util.concurrent.ThreadPoolExecutor中的$ Worker.run(ThreadPoolExecutor.java:581)
03-16 13:56:51.035:D / posttemplate(6479):在java.lang.Thread.run(Thread.java:1019)
conn.disconnect()
在 outputStream.close()
So I'm trying to send a multipart/form-data POST request with large image file. I can't pre-convert file to byte array, my app will crash with OutOfMemory exception, so I have to write contents of the file directly to connection's outputstream. Also, my server doesn't support chunked mode, so I have to calculate content length before sending data and use connection's setFixedLengthStreamingMode.
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
}
}
Unfortunately, my app crashes with IOException at outputStream.close(), and I have no idea why:
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)
conn.disconnect()
after outputStream.close()
这篇关于HttpURLConnection的 - POST的multipart / form-data的大文件FixedLengthStreamingMode的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!