Надсилання файлів за допомогою POST з HttpURLConnection


124

Оскільки розробники Android рекомендують використовувати HttpURLConnectionклас, мені було цікаво, чи може хтось надати мені хороший приклад того, як надіслати растровий файл "файл" (власне потік пам'яті) через POST на сервер HTTP Apache HTTP. Мене не цікавлять файли cookie чи автентифікація чи щось складне, але я просто хочу мати надійну та логічну реалізацію. Усі приклади, які я бачив навколо, виглядають більше як "давайте спробуємо це, і, можливо, це спрацює".

Зараз у мене є цей код:

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();
    }
}

де showDialog повинен просто відображати AlertDialog(у разі недійсної URL-адреси?).

Тепер скажімо, що я генерую растрову карту так: Bitmap image = this.getBitmap()всередині елемента управління, який Viewя отримую, і я хочу надіслати його через POST. Яка була б правильна процедура для досягнення такого? Які класи мені потрібно використовувати? Чи можу я використовувати, HttpPostяк у цьому прикладі ? Якщо так, то як би я сконструював InputStreamEntityдля моєї растрової карти? Мені здається, що потрібно спочатку зберігати растрові файли у файлі на пристрої.


Я також повинен зазначити, що мені дійсно потрібно надсилати кожен незмінний піксель оригінальної растрової карти на сервер, тому я не можу конвертувати його в JPEG.


1
Перегляньте цю дискусію ТАК
Aniket Thakur

Відповіді:


194

Я поняття не маю, чому HttpURLConnectionклас не надає жодних засобів для надсилання файлів без необхідності складати обгортку файлів вручну. Ось що я закінчила, але якщо хтось знає краще рішення, будь ласка, дайте мені знати.

Вхідні дані:

Bitmap bitmap = myView.getBitmap();

Статичні речі:

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

Налаштуйте запит:

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);

Почати обгортку вмісту:

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);

Перетворити Bitmapна 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);

Кінцева обгортка вмісту:

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

Буфер вимивання:

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

Отримати відповідь:

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();

Закрити потік відповідей:

responseStream.close();

Закрийте з'єднання:

httpUrlConnection.disconnect();

PS: Звичайно, мені довелося завершити запит private class AsyncUploadBitmaps extends AsyncTask<Bitmap, Void, String>, щоб зробити платформу Android щасливою, тому що їй не подобається мати мережеві запити в основному потоці.


6
Нарешті ідеально пояснена відповідь на це питання! Дякую! До речі, я щойно знайшов цю статтю з блогу розробників Android ( android-developers.blogspot.com/2011/09/… ), де вони пропонують використовувати HTTPURLCзв’язок через HTTPClient Apache. Ура!
Андрес Пашон

PS: Відповідно до цього , "[error] => 3" означає, що "завантажений файл був завантажений лише частково", тому я можу припустити, що є деякі проблеми з буферизацією, але я не маю уявлення, як налагодити / виправити щось подібне .
Михай Тодор

1
Дивіться мій коментар трохи вище. Вам потрібно , щоб додати їх до urlзмінної, наприклад , так: URL url = new URL("http://example.com/?param1=val1&param2=val2");. Ви можете додати скільки завгодно бажань (хоча, я думаю, є певні обмеження).
Михай Тодор

Відмінно, просто пропускає одне: цей responseStreamReader повинен бути закритий, нарешті, у спробі / уловленні. Таким чином: спробуйте {ALL YOUR CODE} catch (IOException e) {e.printStackTrace (); } нарешті {if (з'єднання! = null) connection.disconnect (); спробуйте {if (responseStreamReader! = null) responseStreamReader.close (); } лов (IOException e) {e.printStackTrace (); }}
FlorianB

2
Ідеальна відповідь! Пропоную поглянути на цей документ w3.org про форми
pippo

68

Я фактично знайшов кращий спосіб надсилання файлів за допомогою HttpURLConnection за допомогою 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();
} 

Припустимо, що ви завантажуєте зображення із растровими даними:

    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);

І Вуаля! Дані вашої публікації будуть містити поле зображення разом із назвою файлу та шляхом на вашому сервері.


1
Я помічаю, що ви не дзвоните на conn.disconnect (), це навмисно?
jerrytouille

1
@MihaiTodor Ви хочете стиснути растровий файл у файл, щоб зменшити обсяг даних, переданих через мережу.
stealthcopter

5
вам слід зателефонувати setFixedLengthStreamingMode (reqEntity.getContentLength ()), а не безпосередньо встановлювати заголовок "Довжина вмісту". Таким чином, ваші дані не буферуються перед надсиланням у сокет (принаймні, на нових пристроях, на android 2.3 або менше, схоже, вони все одно буферуються). Я вирішив проблему буферизації на старих пристроях, використовуючи okhttp як транспорт, і це працює.
Метт Вулф

16
занадто поганий MultipartEntity не в комплекті з Android SDK
менте

2
@mente У комплекті з httpmime. Я використовую це як залежність від Gradle: org.apache.httpcomponents: httpmime: 4.1.1
david.perez

63

Завантажити файл на сервер з деяким параметром, використовуючи MultipartUtilityпростий спосіб.

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();
    }
}

Для uploadвас fileразом з параметрами.

ПРИМІТКА. Поставте цей код нижче в non-u-потоку, щоб отримати відповідь.

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

Розв’язок Джайдіпсіна Зала не працювало для мене, я не знаю, чому, але, здається, воно близьке до рішення.

Тож злиття цього з чудовим рішенням та поясненням Михай Тодора , результат - це клас, який зараз працює для мене. Якщо це комусь допомагає:

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
Це рішення, яке працює тільки для мене. Велике спасибі.
Юсель Байрам

3

Ця відповідь https://stackoverflow.com/a/33149413/6481542 дала мені 90% шляху завантаження великих файлів на сервер Django розвитку, але мені довелося використовувати setFixedLengthStreamingMode, щоб він працював. Для цього потрібно встановити довжину вмісту перед тим, як писати вміст, тим самим вимагаючи досить значного перезапису вищевказаної відповіді. Ось мій кінцевий результат

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();
    }
}

Використання в основному таке ж, як у наведеній вище відповіді, але я включив підтримку CSRF, яку Django використовує за замовчуванням у формах

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

базуючись на рішенні Міхай, якщо у когось є проблема збереження зображень на сервері, як це було на моєму сервері. змінити біт-карту на частину байт-буфера на:

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

1

Я цього не перевіряв, але ви можете спробувати використовувати PipedInputStream і PipedOutputStream. Це може виглядати приблизно так:

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

Ось що я зробив для завантаження фотографії за допомогою поштового запиту.

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());
    }
}

Примітка: Цей код вимагає бібліотек так , дотримуйтесь інструкцій тут , щоб отримати бібліотеки.


2
Це добре , щоб знати , що є спосіб , щоб використовувати останню версію HttpClient(ваша посилання застаріло. Використовуйте цей замість), яку Android хлопці тримають тільки для зворотної сумісності, а не використовувати вбудований HttpURLConnection. З іншого боку, схоже, що для її налаштування потрібно більше роботи, тому, можливо, не варто докладати зусиль.
Михай Тодор


0

Я спробував рішення вище, і жоден не працював для мене поза коробкою.

Однак http://www.baeldung.com/httpclient-post-http-request . Рядок 6 Запит на багаточастковий пост відпрацьований протягом декількох секунд

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();
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.