HttpURLConnection的 - POST的multipart / form-data的大文件FixedLengthStreamingMode [英] HTTPURLConnection - POST multipart/form-data with large file with FixedLengthStreamingMode

查看:346
本文介绍了HttpURLConnection的 - POST的multipart / form-data的大文件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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆