2012-03-16 14 views
6

Vì vậy, tôi đang cố gắng gửi yêu cầu POST nhiều phần/biểu mẫu dữ liệu với tệp hình ảnh lớn. Tôi không thể chuyển đổi tập tin thành mảng byte, ứng dụng của tôi sẽ bị lỗi với ngoại lệ OutOfMemory, vì vậy tôi phải ghi nội dung của tệp trực tiếp vào đầu ra của kết nối. Ngoài ra, máy chủ của tôi không hỗ trợ chế độ chunked, vì vậy tôi phải tính toán độ dài nội dung trước khi gửi dữ liệu và sử dụng setFixedLengthStreamingMode của kết nối.HTTPURLConnection - Bối cảnh/dữ liệu biểu mẫu POST với tệp lớn với 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 
    }   

} 

Thật không may, tai nạn của tôi ứng dụng với IOException tại outputStream.close(), và tôi không có ý tưởng tại sao:

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) 

Trả lời

5

conn.disconnect() sau outputStream.close()

1

Để biết thông tin của bạn, mã của bạn nên làm việc tốt với kết nối HTTP URL, nhưng HTTPS sẽ kích hoạt lỗi Out of Memory vì có lỗi trong HttpsURLConnectionImpl.java trong Android 2.3.4 (đã được xác minh trên máy tính bảng của tôi) và lỗi này đã được sửa trong Android 4.1 (tôi đã kiểm tra nguồn mã).

+0

Ông có thể chỉ cho tôi lỗi này mà bạn đề cập đến? Tôi dường như đang chạy vào cùng một vấn đề bằng cách sử dụng HttpsUrlConnection trên Gingerbread. – HungryTux

2

Tiêu đề HTTP không phải là một phần của nội dung, do đó, không tính đến chúng cho độ dài cơ thể.

stringForLength += "Content-Type: multipart/form-data;boundary=" + boundary; 

xóa dòng trên, do đó bạn chiều dài nội dung sẽ chính xác.

0
int totalLength = stringForLength.length() + (int)file.length(); 

Mã trên của bạn sai.

Bạn nên sử dụng độ dài byte của chuỗi như sau

int totalLength = stringForLength.getBytes().length + (int)file.length(); 
Các vấn đề liên quan