Gửi tệp bằng POST với kết nối httpURLC


124

Vì các nhà phát triển Android khuyên bạn nên sử dụng HttpURLConnectionlớp, tôi đã tự hỏi liệu có ai có thể cung cấp cho tôi một ví dụ hay về cách gửi "tệp" bitmap (thực sự là một luồng trong bộ nhớ) qua POST đến máy chủ HTTP Apache không. Tôi không quan tâm đến cookie hoặc xác thực hoặc bất cứ điều gì phức tạp, nhưng tôi chỉ muốn có một triển khai logic và đáng tin cậy. Tất cả các ví dụ mà tôi đã thấy xung quanh đây trông giống như "hãy thử cái này và có thể nó hoạt động".

Ngay bây giờ, tôi có mã này:

URL url;
HttpURLConnection urlConnection = null;
try {
    url = new URL("http://example.com/server.cgi");

    urlConnection = (HttpURLConnection) url.openConnection();

} catch (Exception e) {
    this.showDialog(getApplicationContext(), e.getMessage());
}
finally {
    if (urlConnection != null)
    {
        urlConnection.disconnect();
    }
}

trong đó showDialog chỉ nên hiển thị AlertDialog(trong trường hợp URL không hợp lệ?).

Bây giờ, giả sử rằng tôi tạo ra một bitmap như vậy: Bitmap image = this.getBitmap()bên trong một điều khiển xuất phát từ Viewvà tôi muốn gửi nó qua POST. Điều gì sẽ là thủ tục thích hợp để đạt được một điều như vậy? Những lớp nào tôi cần sử dụng? Tôi có thể sử dụng HttpPostnhư trong ví dụ này không? Nếu vậy, tôi sẽ xây dựng InputStreamEntitybitmap như thế nào? Tôi sẽ thấy nó nổi loạn khi được yêu cầu lưu trữ bitmap đầu tiên trong một tệp trên thiết bị.


Tôi cũng nên đề cập rằng tôi thực sự cần gửi mọi pixel chưa được thay đổi của bitmap gốc tới máy chủ, vì vậy tôi không thể chuyển đổi nó thành JPEG.


Câu trả lời:


194

Tôi không biết tại sao HttpURLConnectionlớp không cung cấp bất kỳ phương tiện nào để gửi tệp mà không phải soạn trình bao bọc tệp theo cách thủ công. Đây là những gì tôi đã làm, nhưng nếu ai đó biết một giải pháp tốt hơn, xin vui lòng cho tôi biết.

Dữ liệu đầu vào:

Bitmap bitmap = myView.getBitmap();

Nội dung tĩnh:

String attachmentName = "bitmap";
String attachmentFileName = "bitmap.bmp";
String crlf = "\r\n";
String twoHyphens = "--";
String boundary =  "*****";

Thiết lập yêu cầu:

HttpURLConnection httpUrlConnection = null;
URL url = new URL("http://example.com/server.cgi");
httpUrlConnection = (HttpURLConnection) url.openConnection();
httpUrlConnection.setUseCaches(false);
httpUrlConnection.setDoOutput(true);

httpUrlConnection.setRequestMethod("POST");
httpUrlConnection.setRequestProperty("Connection", "Keep-Alive");
httpUrlConnection.setRequestProperty("Cache-Control", "no-cache");
httpUrlConnection.setRequestProperty(
    "Content-Type", "multipart/form-data;boundary=" + this.boundary);

Bắt đầu trình bao bọc nội dung:

DataOutputStream request = new DataOutputStream(
    httpUrlConnection.getOutputStream());

request.writeBytes(this.twoHyphens + this.boundary + this.crlf);
request.writeBytes("Content-Disposition: form-data; name=\"" +
    this.attachmentName + "\";filename=\"" + 
    this.attachmentFileName + "\"" + this.crlf);
request.writeBytes(this.crlf);

Chuyển đổi Bitmapsang ByteBuffer:

//I want to send only 8 bit black & white bitmaps
byte[] pixels = new byte[bitmap.getWidth() * bitmap.getHeight()];
for (int i = 0; i < bitmap.getWidth(); ++i) {
    for (int j = 0; j < bitmap.getHeight(); ++j) {
        //we're interested only in the MSB of the first byte, 
        //since the other 3 bytes are identical for B&W images
        pixels[i + j] = (byte) ((bitmap.getPixel(i, j) & 0x80) >> 7);
    }
}

request.write(pixels);

Kết thúc trình bao bọc nội dung:

request.writeBytes(this.crlf);
request.writeBytes(this.twoHyphens + this.boundary + 
    this.twoHyphens + this.crlf);

Bộ đệm đầu ra:

request.flush();
request.close();

Nhận được phản ứng:

InputStream responseStream = new 
    BufferedInputStream(httpUrlConnection.getInputStream());

BufferedReader responseStreamReader = 
    new BufferedReader(new InputStreamReader(responseStream));

String line = "";
StringBuilder stringBuilder = new StringBuilder();

while ((line = responseStreamReader.readLine()) != null) {
    stringBuilder.append(line).append("\n");
}
responseStreamReader.close();

String response = stringBuilder.toString();

Đóng luồng phản hồi:

responseStream.close();

Đóng kết nối:

httpUrlConnection.disconnect();

PS: Tất nhiên tôi phải gói yêu cầu private class AsyncUploadBitmaps extends AsyncTask<Bitmap, Void, String>, để làm cho nền tảng Android hài ​​lòng, vì nó không muốn có các yêu cầu mạng trên luồng chính.


6
Cuối cùng một câu trả lời giải thích hoàn hảo cho câu hỏi này! Cảm ơn bạn! BTW, tôi chỉ tìm thấy bài viết này từ Blog nhà phát triển Android ( android-developers.blogspot.com/2011/09/... ) nơi họ đề nghị sử dụng HTTPURLConnection so với Apache HttpClient. Chúc mừng!
Andrés Pachon

PS: Theo đó , `[error] => 3` có nghĩa là" tệp được tải lên chỉ được tải lên một phần ", vì vậy tôi có thể giả sử rằng có một số vấn đề về bộ đệm, nhưng tôi không biết làm thế nào để gỡ lỗi / sửa lỗi như thế này .
Mihai Todor

1
Xem bình luận của tôi ở trên. Bạn cần thêm chúng vào urlbiến, như vậy : URL url = new URL("http://example.com/?param1=val1&param2=val2");. Bạn có thể thêm bao nhiêu tùy ý (mặc dù tôi nghĩ rằng có một số giới hạn).
Mihai Todor

Tuyệt vời, chỉ cần bỏ lỡ một điều: phản hồi đó sẽ được đóng lại sau khi thử / bắt. Bằng cách này: thử {TẤT CẢ MÃ CỦA BẠN} bắt (IOException e) {e.printStackTrace (); } cuối cùng {if (kết nối! = null) Connection.disconnect (); thử {if (answerStreamReader! = null) answerStreamReader.close (); } Catch (IOException e) {e.printStackTrace (); }}
FlorianB

2
Câu trả lời hoàn hảo! Tôi đề nghị xem qua tài liệu w3.org này về các biểu mẫu
pippo

68

Tôi thực sự tìm thấy một cách tốt hơn để gửi các tệp bằng cách sử dụng httpURLConnection bằng MultipartEntity

private static String multipost(String urlString, MultipartEntity reqEntity) {
    try {
        URL url = new URL(urlString);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setReadTimeout(10000);
        conn.setConnectTimeout(15000);
        conn.setRequestMethod("POST");
        conn.setUseCaches(false);
        conn.setDoInput(true);
        conn.setDoOutput(true);

        conn.setRequestProperty("Connection", "Keep-Alive");
        conn.addRequestProperty("Content-length", reqEntity.getContentLength()+"");
        conn.addRequestProperty(reqEntity.getContentType().getName(), reqEntity.getContentType().getValue());

        OutputStream os = conn.getOutputStream();
        reqEntity.writeTo(conn.getOutputStream());
        os.close();
        conn.connect();

        if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
            return readStream(conn.getInputStream());
        }

    } catch (Exception e) {
        Log.e(TAG, "multipart post error " + e + "(" + urlString + ")");
    }
    return null;        
}

private static String readStream(InputStream in) {
    BufferedReader reader = null;
    StringBuilder builder = new StringBuilder();
    try {
        reader = new BufferedReader(new InputStreamReader(in));
        String line = "";
        while ((line = reader.readLine()) != null) {
            builder.append(line);
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (reader != null) {
            try {
                reader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    return builder.toString();
} 

Giả sử bạn đang tải lên một hình ảnh với dữ liệu bitmap:

    Bitmap bitmap = ...;
    String filename = "filename.png";
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    bitmap.compress(Bitmap.CompressFormat.PNG, 100, bos);
    ContentBody contentPart = new ByteArrayBody(bos.toByteArray(), filename);

    MultipartEntity reqEntity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
    reqEntity.addPart("picture", contentPart);
    String response = multipost("http://server.com", reqEntity);

Và Voila! Dữ liệu bài đăng của bạn sẽ chứa trường hình ảnh cùng với tên tệp và đường dẫn trên máy chủ của bạn.


1
Tôi nhận thấy bạn không gọi Conn.disconnect (), có phải là cố ý không?
jerrytouille

1
@MihaiTodor Bạn sẽ muốn nén bitmap vào Tệp để giảm lượng dữ liệu được truyền qua mạng.
tàng hình

5
bạn nên gọi setFixedL wavelStreamingMode (reqEntity.getContentL wavel ()) thay vì đặt trực tiếp tiêu đề Độ dài nội dung. Bằng cách này, dữ liệu của bạn không được đệm trước khi gửi trên ổ cắm (ít nhất là trên các thiết bị mới hơn, trên Android 2.3 hoặc ít hơn có vẻ như chúng được đệm bất kỳ cách nào). Tôi đã khắc phục sự cố bộ đệm trên các thiết bị cũ hơn bằng cách sử dụng okhttp làm phương tiện vận chuyển và nó hoạt động.
Matt Wolfe

16
quá tệ MultipartEntity không được gói cùng với SDK Android
mente

2
@mente Nó được gói cùng với httpmime. Tôi sử dụng điều này như một phụ thuộc Gradle: org.apache.httpcomponents: httpmime: 4.1.1
david.perez

63

Để tải lên tệp trên máy chủ với một số tham số bằng cách sử dụng MultipartUtilityđơn giản.

MultipartUtility.java

public class MultipartUtility {

    private final String boundary;
    private static final String LINE_FEED = "\r\n";
    private HttpURLConnection httpConn;
    private String charset;
    private OutputStream outputStream;
    private PrintWriter writer;

    /**
     * This constructor initializes a new HTTP POST request with content type
     * is set to multipart/form-data
     *
     * @param requestURL
     * @param charset
     * @throws IOException
     */
    public MultipartUtility(String requestURL, String charset)
            throws IOException {
        this.charset = charset;

        // creates a unique boundary based on time stamp
        boundary = "===" + System.currentTimeMillis() + "===";

        URL url = new URL(requestURL);
        Log.e("URL", "URL : " + requestURL.toString());
        httpConn = (HttpURLConnection) url.openConnection();
        httpConn.setUseCaches(false);
        httpConn.setDoOutput(true); // indicates POST method
        httpConn.setDoInput(true);
        httpConn.setRequestProperty("Content-Type",
                "multipart/form-data; boundary=" + boundary);
        httpConn.setRequestProperty("User-Agent", "CodeJava Agent");
        httpConn.setRequestProperty("Test", "Bonjour");
        outputStream = httpConn.getOutputStream();
        writer = new PrintWriter(new OutputStreamWriter(outputStream, charset),
                true);
    }

    /**
     * Adds a form field to the request
     *
     * @param name  field name
     * @param value field value
     */
    public void addFormField(String name, String value) {
        writer.append("--" + boundary).append(LINE_FEED);
        writer.append("Content-Disposition: form-data; name=\"" + name + "\"")
                .append(LINE_FEED);
        writer.append("Content-Type: text/plain; charset=" + charset).append(
                LINE_FEED);
        writer.append(LINE_FEED);
        writer.append(value).append(LINE_FEED);
        writer.flush();
    }

    /**
     * Adds a upload file section to the request
     *
     * @param fieldName  name attribute in <input type="file" name="..." />
     * @param uploadFile a File to be uploaded
     * @throws IOException
     */
    public void addFilePart(String fieldName, File uploadFile)
            throws IOException {
        String fileName = uploadFile.getName();
        writer.append("--" + boundary).append(LINE_FEED);
        writer.append(
                "Content-Disposition: form-data; name=\"" + fieldName
                        + "\"; filename=\"" + fileName + "\"")
                .append(LINE_FEED);
        writer.append(
                "Content-Type: "
                        + URLConnection.guessContentTypeFromName(fileName))
                .append(LINE_FEED);
        writer.append("Content-Transfer-Encoding: binary").append(LINE_FEED);
        writer.append(LINE_FEED);
        writer.flush();

        FileInputStream inputStream = new FileInputStream(uploadFile);
        byte[] buffer = new byte[4096];
        int bytesRead = -1;
        while ((bytesRead = inputStream.read(buffer)) != -1) {
            outputStream.write(buffer, 0, bytesRead);
        }
        outputStream.flush();
        inputStream.close();

        writer.append(LINE_FEED);
        writer.flush();
    }

    /**
     * Adds a header field to the request.
     *
     * @param name  - name of the header field
     * @param value - value of the header field
     */
    public void addHeaderField(String name, String value) {
        writer.append(name + ": " + value).append(LINE_FEED);
        writer.flush();
    }

    /**
     * Completes the request and receives response from the server.
     *
     * @return a list of Strings as response in case the server returned
     * status OK, otherwise an exception is thrown.
     * @throws IOException
     */
    public String finish() throws IOException {
        StringBuffer response = new StringBuffer();

        writer.append(LINE_FEED).flush();
        writer.append("--" + boundary + "--").append(LINE_FEED);
        writer.close();

        // checks server's status code first
        int status = httpConn.getResponseCode();
        if (status == HttpURLConnection.HTTP_OK) {
            BufferedReader reader = new BufferedReader(new InputStreamReader(
                    httpConn.getInputStream()));
            String line = null;
            while ((line = reader.readLine()) != null) {
                response.append(line);
            }
            reader.close();
            httpConn.disconnect();
        } else {
            throw new IOException("Server returned non-OK status: " + status);
        }

        return response.toString();
    }
}

Để uploadbạn filecùng với các thông số.

LƯU Ý: đặt mã này bên dưới trong luồng không ui để nhận phản hồi.

String charset = "UTF-8";
String requestURL = "YOUR_URL";

MultipartUtility multipart = new MultipartUtility(requestURL, charset);
multipart.addFormField("param_name_1", "param_value");
multipart.addFormField("param_name_2", "param_value");
multipart.addFormField("param_name_3", "param_value");
multipart.addFilePart("file_param_1", new File(file_path));
String response = multipart.finish(); // response from server.

14

Giải pháp của Jaydipsinh Zala không hiệu quả với tôi, tôi không biết tại sao nhưng dường như nó gần với giải pháp.

Vì vậy, việc hợp nhất giải pháp này với giải pháp và giải thích tuyệt vời của Mihai Todor , kết quả là lớp học này hiện đang hoạt động với tôi. Nếu nó giúp được ai đó:

MultipartUtility2V.java

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.file.Files;

public class MultipartUtilityV2 {
    private HttpURLConnection httpConn;
    private DataOutputStream request;
    private final String boundary =  "*****";
    private final String crlf = "\r\n";
    private final String twoHyphens = "--";

    /**
     * This constructor initializes a new HTTP POST request with content type
     * is set to multipart/form-data
     *
     * @param requestURL
     * @throws IOException
     */
    public MultipartUtilityV2(String requestURL)
            throws IOException {

        // creates a unique boundary based on time stamp
        URL url = new URL(requestURL);
        httpConn = (HttpURLConnection) url.openConnection();
        httpConn.setUseCaches(false);
        httpConn.setDoOutput(true); // indicates POST method
        httpConn.setDoInput(true);

        httpConn.setRequestMethod("POST");
        httpConn.setRequestProperty("Connection", "Keep-Alive");
        httpConn.setRequestProperty("Cache-Control", "no-cache");
        httpConn.setRequestProperty(
                "Content-Type", "multipart/form-data;boundary=" + this.boundary);

        request =  new DataOutputStream(httpConn.getOutputStream());
    }

    /**
     * Adds a form field to the request
     *
     * @param name  field name
     * @param value field value
     */
    public void addFormField(String name, String value)throws IOException  {
        request.writeBytes(this.twoHyphens + this.boundary + this.crlf);
        request.writeBytes("Content-Disposition: form-data; name=\"" + name + "\""+ this.crlf);
        request.writeBytes("Content-Type: text/plain; charset=UTF-8" + this.crlf);
        request.writeBytes(this.crlf);
        request.writeBytes(value+ this.crlf);
        request.flush();
    }

    /**
     * Adds a upload file section to the request
     *
     * @param fieldName  name attribute in <input type="file" name="..." />
     * @param uploadFile a File to be uploaded
     * @throws IOException
     */
    public void addFilePart(String fieldName, File uploadFile)
            throws IOException {
        String fileName = uploadFile.getName();
        request.writeBytes(this.twoHyphens + this.boundary + this.crlf);
        request.writeBytes("Content-Disposition: form-data; name=\"" +
                fieldName + "\";filename=\"" +
                fileName + "\"" + this.crlf);
        request.writeBytes(this.crlf);

        byte[] bytes = Files.readAllBytes(uploadFile.toPath());
        request.write(bytes);
    }

    /**
     * Completes the request and receives response from the server.
     *
     * @return a list of Strings as response in case the server returned
     * status OK, otherwise an exception is thrown.
     * @throws IOException
     */
    public String finish() throws IOException {
        String response ="";

        request.writeBytes(this.crlf);
        request.writeBytes(this.twoHyphens + this.boundary +
                this.twoHyphens + this.crlf);

        request.flush();
        request.close();

        // checks server's status code first
        int status = httpConn.getResponseCode();
        if (status == HttpURLConnection.HTTP_OK) {
            InputStream responseStream = new
                    BufferedInputStream(httpConn.getInputStream());

            BufferedReader responseStreamReader =
                    new BufferedReader(new InputStreamReader(responseStream));

            String line = "";
            StringBuilder stringBuilder = new StringBuilder();

            while ((line = responseStreamReader.readLine()) != null) {
                stringBuilder.append(line).append("\n");
            }
            responseStreamReader.close();

            response = stringBuilder.toString();
            httpConn.disconnect();
        } else {
            throw new IOException("Server returned non-OK status: " + status);
        }

        return response;
    }
}

1
Đây là giải pháp chỉ làm việc cho tôi. Cảm ơn rât nhiều.
Yucel Bayram

3

Câu trả lời này https://stackoverflow.com/a/33149413/6481542 đã giúp tôi 90% cách tải các tệp lớn lên máy chủ Django phát triển, nhưng tôi đã phải sử dụng setFixedLạngStreamingMode để làm cho nó hoạt động. Điều đó đòi hỏi phải thiết lập Độ dài nội dung trước khi viết nội dung, do đó yêu cầu viết lại khá quan trọng câu trả lời ở trên. Đây là kết quả cuối cùng của tôi

public class MultipartLargeUtility {
    private final String boundary;
    private static final String LINE_FEED = "\r\n";
    private HttpURLConnection httpConn;
    private String charset;
    private OutputStream outputStream;
    private PrintWriter writer;
    private final int maxBufferSize = 4096;
    private long contentLength = 0;
    private URL url;

    private List<FormField> fields;
    private List<FilePart> files;

    private class FormField {
        public String name;
        public String value;

        public FormField(String name, String value) {
            this.name = name;
            this.value = value;
        }
    }

    private class FilePart {
        public String fieldName;
        public File uploadFile;

        public FilePart(String fieldName, File uploadFile) {
            this.fieldName = fieldName;
            this.uploadFile = uploadFile;
        }
    }

    /**
     * This constructor initializes a new HTTP POST request with content type
     * is set to multipart/form-data
     *
     * @param requestURL
     * @param charset
     * @throws IOException
     */
    public MultipartLargeUtility(String requestURL, String charset, boolean requireCSRF)
            throws IOException {
        this.charset = charset;

        // creates a unique boundary based on time stamp
        boundary = "===" + System.currentTimeMillis() + "===";
        url = new URL(requestURL);
        fields = new ArrayList<>();
        files = new ArrayList<>();

        if (requireCSRF) {
            getCSRF();
        }
    }

    /**
     * Adds a form field to the request
     *
     * @param name  field name
     * @param value field value
     */
    public void addFormField(String name, String value)
            throws UnsupportedEncodingException {
        String fieldContent = "--" + boundary + LINE_FEED;
        fieldContent += "Content-Disposition: form-data; name=\"" + name + "\"" + LINE_FEED;
        fieldContent += "Content-Type: text/plain; charset=" + charset + LINE_FEED;
        fieldContent += LINE_FEED;
        fieldContent += value + LINE_FEED;
        contentLength += fieldContent.getBytes(charset).length;
        fields.add(new FormField(name, value));
    }

    /**
     * Adds a upload file section to the request
     *
     * @param fieldName  name attribute in <input type="file" name="..." />
     * @param uploadFile a File to be uploaded
     * @throws IOException
     */
    public void addFilePart(String fieldName, File uploadFile)
            throws IOException {
        String fileName = uploadFile.getName();

        String fieldContent = "--" + boundary + LINE_FEED;
        fieldContent += "Content-Disposition: form-data; name=\"" + fieldName
                + "\"; filename=\"" + fileName + "\"" + LINE_FEED;
        fieldContent += "Content-Type: "
                + URLConnection.guessContentTypeFromName(fileName) + LINE_FEED;
        fieldContent += "Content-Transfer-Encoding: binary" + LINE_FEED;
        fieldContent += LINE_FEED;
        // file content would go here
        fieldContent += LINE_FEED;
        contentLength += fieldContent.getBytes(charset).length;
        contentLength += uploadFile.length();
        files.add(new FilePart(fieldName, uploadFile));
    }

    /**
     * Adds a header field to the request.
     *
     * @param name  - name of the header field
     * @param value - value of the header field
     */
    //public void addHeaderField(String name, String value) {
    //    writer.append(name + ": " + value).append(LINE_FEED);
    //    writer.flush();
    //}

    /**
     * Completes the request and receives response from the server.
     *
     * @return a list of Strings as response in case the server returned
     * status OK, otherwise an exception is thrown.
     * @throws IOException
     */
    public List<String> finish() throws IOException {
        List<String> response = new ArrayList<String>();
        String content = "--" + boundary + "--" + LINE_FEED;
        contentLength += content.getBytes(charset).length;

        if (!openConnection()) {
            return response;
        }

        writeContent();

        // checks server's status code first
        int status = httpConn.getResponseCode();
        if (status == HttpURLConnection.HTTP_OK) {
            BufferedReader reader = new BufferedReader(new InputStreamReader(
                    httpConn.getInputStream()));
            String line = null;
            while ((line = reader.readLine()) != null) {
                response.add(line);
            }
            reader.close();
            httpConn.disconnect();
        } else {
            throw new IOException("Server returned non-OK status: " + status);
        }
        return response;
    }

    private boolean getCSRF()
            throws IOException {
        /// First, need to get CSRF token from server
        /// Use GET request to get the token
        CookieManager cookieManager = new CookieManager();
        CookieHandler.setDefault(cookieManager);
        HttpURLConnection conn = null;

        conn = (HttpURLConnection) url.openConnection();

        conn.setUseCaches(false); // Don't use a Cached Copy
        conn.setRequestMethod("GET");
        conn.setRequestProperty("Connection", "Keep-Alive");
        conn.getContent();
        conn.disconnect();

        /// parse the returned object for the CSRF token
        CookieStore cookieJar = cookieManager.getCookieStore();
        List<HttpCookie> cookies = cookieJar.getCookies();
        String csrf = null;
        for (HttpCookie cookie : cookies) {
            Log.d("cookie", "" + cookie);
            if (cookie.getName().equals("csrftoken")) {
                csrf = cookie.getValue();
                break;
            }
        }
        if (csrf == null) {
            Log.d(TAG, "Unable to get CSRF");
            return false;
        }
        Log.d(TAG, "Received cookie: " + csrf);

        addFormField("csrfmiddlewaretoken", csrf);
        return true;
    }

    private boolean openConnection()
            throws IOException {
        httpConn = (HttpURLConnection) url.openConnection();
        httpConn.setUseCaches(false);
        httpConn.setDoOutput(true);    // indicates POST method
        httpConn.setDoInput(true);
        //httpConn.setRequestProperty("Accept-Encoding", "identity");
        httpConn.setFixedLengthStreamingMode(contentLength);
        httpConn.setRequestProperty("Connection", "Keep-Alive");
        httpConn.setRequestProperty("Content-Type",
                "multipart/form-data; boundary=" + boundary);
        outputStream = new BufferedOutputStream(httpConn.getOutputStream());
        writer = new PrintWriter(new OutputStreamWriter(outputStream, charset),
                true);
        return true;
    }

    private void writeContent()
            throws IOException {

        for (FormField field : fields) {
            writer.append("--" + boundary).append(LINE_FEED);
            writer.append("Content-Disposition: form-data; name=\"" + field.name + "\"")
                    .append(LINE_FEED);
            writer.append("Content-Type: text/plain; charset=" + charset).append(
                    LINE_FEED);
            writer.append(LINE_FEED);
            writer.append(field.value).append(LINE_FEED);
            writer.flush();
        }

        for (FilePart filePart : files) {
            String fileName = filePart.uploadFile.getName();
            writer.append("--" + boundary).append(LINE_FEED);
            writer.append(
                    "Content-Disposition: form-data; name=\"" + filePart.fieldName
                            + "\"; filename=\"" + fileName + "\"")
                    .append(LINE_FEED);
            writer.append(
                    "Content-Type: "
                            + URLConnection.guessContentTypeFromName(fileName))
                    .append(LINE_FEED);
            writer.append("Content-Transfer-Encoding: binary").append(LINE_FEED);
            writer.append(LINE_FEED);
            writer.flush();

            FileInputStream inputStream = new FileInputStream(filePart.uploadFile);
            int bufferSize = Math.min(inputStream.available(), maxBufferSize);
            byte[] buffer = new byte[bufferSize];
            int bytesRead = -1;
            while ((bytesRead = inputStream.read(buffer, 0, bufferSize)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }
            outputStream.flush();
            inputStream.close();
            writer.append(LINE_FEED);
            writer.flush();
        }

        writer.append("--" + boundary + "--").append(LINE_FEED);
        writer.close();
    }
}

Cách sử dụng phần lớn giống như trong câu trả lời ở trên, nhưng tôi đã bao gồm hỗ trợ CSRF mà Django sử dụng theo mặc định với các biểu mẫu

boolean useCSRF = true;
MultipartLargeUtility multipart = new MultipartLargeUtility(url, "UTF-8",useCSRF);
multipart.addFormField("param1","value");
multipart.addFilePart("filefield",new File("/path/to/file"));
List<String> response = multipart.finish();
Log.w(TAG,"SERVER REPLIED:");
for(String line : response) {
    Log.w(TAG, "Upload Files Response:::" + line);
}

2

dựa trên giải pháp của Mihai, nếu có ai gặp vấn đề về lưu ảnh trên máy chủ như những gì đã xảy ra trên máy chủ của tôi. thay đổi phần Bitmap thành phần bytebuffer thành:

ByteArrayOutputStream bos = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.JPEG,100,bos);
        byte[] pixels = bos.toByteArray();

1

Tôi chưa thử nghiệm điều này, nhưng bạn có thể thử sử dụng PipedInputStream và PipedOutputStream. Nó có thể trông giống như:

final Bitmap bmp =  // your bitmap

// Set up Piped streams
final PipedOutputStream pos = new PipedOutputStream(new ByteArrayOutputStream());
final PipedInputStream pis = new PipedInputStream(pos);

// Send bitmap data to the PipedOutputStream in a separate thread
new Thread() {
    public void run() {
        bmp.compress(Bitmap.CompressFormat.PNG, 100, pos);
    }
}.start();

// Send POST request
try {
    // Construct InputStreamEntity that feeds off of the PipedInputStream
    InputStreamEntity reqEntity = new InputStreamEntity(pis, -1);

    HttpClient httpclient = new DefaultHttpClient();
    HttpPost httppost = new HttpPost(url);
    reqEntity.setContentType("binary/octet-stream");
    reqEntity.setChunked(true);
    httppost.setEntity(reqEntity);
    HttpResponse response = httpclient.execute(httppost);
} catch (Exception e) {
    e.printStackTrace()
}

0

Đây là những gì tôi đã làm để tải lên hình ảnh bằng cách sử dụng yêu cầu bài viết.

public void uploadFile(int directoryID, String filePath) {
    Bitmap bitmapOrg = BitmapFactory.decodeFile(filePath);
    ByteArrayOutputStream bao = new ByteArrayOutputStream();

    String upload_url = BASE_URL + UPLOAD_FILE;
    bitmapOrg.compress(Bitmap.CompressFormat.JPEG, 90, bao);

    byte[] data = bao.toByteArray();

    HttpClient httpClient = new DefaultHttpClient();
    HttpPost postRequest = new HttpPost(upload_url);
    MultipartEntity entity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);

    try {
        // Set Data and Content-type header for the image
        FileBody fb = new FileBody(new File(filePath), "image/jpeg");
        StringBody contentString = new StringBody(directoryID + "");

        entity.addPart("file", fb);
        entity.addPart("directory_id", contentString);
        postRequest.setEntity(entity);

        HttpResponse response = httpClient.execute(postRequest);
        // Read the response
        String jsonString = EntityUtils.toString(response.getEntity());
        Log.e("response after uploading file ", jsonString);

    } catch (Exception e) {
        Log.e("Error in uploadFile", e.getMessage());
    }
}

LƯU Ý: Mã này yêu cầu các thư viện vì vậy hãy làm theo các hướng dẫn ở đây để có được các thư viện.


2
Thật tốt khi biết rằng có một cách để sử dụng phiên bản mới nhất HttpClient(liên kết của bạn đã lỗi thời. Thay vào đó hãy sử dụng phiên bản này ), mà các nhân viên Android chỉ giữ lại để tương thích ngược, thay vì sử dụng tích hợp HttpURLConnection. Mặt khác, có vẻ như nó đòi hỏi nhiều công việc hơn để thiết lập nó, vì vậy có lẽ nó không đáng để nỗ lực.
Mihai Todor


0

Tôi đã thử các giải pháp trên và không có giải pháp nào cho tôi ra khỏi hộp.

Tuy nhiên http://www.baeldung.com/httpclient-post-http-request . Dòng 6 Yêu cầu đa mục POST hoạt động trong vòng vài giây

public void whenSendMultipartRequestUsingHttpClient_thenCorrect() 
  throws ClientProtocolException, IOException {
    CloseableHttpClient client = HttpClients.createDefault();
    HttpPost httpPost = new HttpPost("http://www.example.com");

    MultipartEntityBuilder builder = MultipartEntityBuilder.create();
    builder.addTextBody("username", "John");
    builder.addTextBody("password", "pass");
    builder.addBinaryBody("file", new File("test.txt"),
      ContentType.APPLICATION_OCTET_STREAM, "file.ext");

    HttpEntity multipart = builder.build();
    httpPost.setEntity(multipart);

    CloseableHttpResponse response = client.execute(httpPost);
    client.close();
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.