«1. Обзор

В этом руководстве мы покажем, как выполнить многоэтапную операцию загрузки с помощью HttpClient 4.

Мы будем использовать http://echo.200please.com в качестве тестового сервера, поскольку он является общедоступным и принимает большинство типов контента.

Если вы хотите копнуть глубже и узнать о других интересных вещах, которые можно делать с помощью HttpClient, перейдите к основному руководству по HttpClient.

2. Использование метода AddPart

Давайте начнем с рассмотрения объекта MultipartEntityBuilder, чтобы добавить части к объекту Http, который затем будет загружен с помощью операции POST.

Это общий метод добавления частей в HttpEntity, представляющий форму.

Пример 2.1. – Загрузка формы с двумя текстовыми частями и файлом

File file = new File(textFileName);
HttpPost post = new HttpPost("http://echo.200please.com");
FileBody fileBody = new FileBody(file, ContentType.DEFAULT_BINARY);
StringBody stringBody1 = new StringBody("Message 1", ContentType.MULTIPART_FORM_DATA);
StringBody stringBody2 = new StringBody("Message 2", ContentType.MULTIPART_FORM_DATA);
// 
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
builder.addPart("upfile", fileBody);
builder.addPart("text1", stringBody1);
builder.addPart("text2", stringBody2);
HttpEntity entity = builder.build();
//
post.setEntity(entity);
HttpResponse response = client.execute(post);

Обратите внимание, что мы создаем экземпляр объекта File, также указав значение ContentType, которое будет использоваться сервером.

Также обратите внимание, что метод addPart имеет два аргумента, действующих как пары ключ/значение для формы. Они имеют значение только в том случае, если серверная сторона действительно ожидает и использует имена параметров — в противном случае они просто игнорируются.

3. Использование методов addBinaryBody и addTextBody

Более прямым способом создания составного объекта является использование методов addBinaryBody и AddTextBody. Эти методы работают для загрузки текста, файлов, массивов символов и объектов InputStream. Поясним, как это сделать, на простых примерах.

Пример 3.1. – Загрузка текста и части текстового файла

HttpPost post = new HttpPost("http://echo.200please.com");
File file = new File(textFileName);
String message = "This is a multipart post";
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
builder.addBinaryBody("upfile", file, ContentType.DEFAULT_BINARY, textFileName);
builder.addTextBody("text", message, ContentType.DEFAULT_BINARY);
// 
HttpEntity entity = builder.build();
post.setEntity(entity);
HttpResponse response = client.execute(post);

Обратите внимание, что объекты FileBody и StringBody здесь не нужны.

Также важно, что большинство серверов не проверяют ContentType основного текста, поэтому метод addTextBody может опускать значение ContentType.

API addBinaryBody принимает ContentType, но также возможно создать объект только из двоичного тела и имени параметра формы, содержащего файл. Как указано в предыдущем разделе, некоторые серверы не распознают файл, если значение ContentType не указано.

Далее мы добавим zip-файл как InputStream, а файл изображения будет добавлен как объект File:

Пример 3.2. – Загрузка ZIP-файла, файла изображения и текстовой части

HttpPost post = new HttpPost("http://echo.200please.com");
InputStream inputStream = new FileInputStream(zipFileName);
File file = new File(imageFileName);
String message = "This is a multipart post";
MultipartEntityBuilder builder = MultipartEntityBuilder.create();         
builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
builder.addBinaryBody
  ("upfile", file, ContentType.DEFAULT_BINARY, imageFileName);
builder.addBinaryBody
  ("upstream", inputStream, ContentType.create("application/zip"), zipFileName);
builder.addTextBody("text", message, ContentType.TEXT_PLAIN);
// 
HttpEntity entity = builder.build();
post.setEntity(entity);
HttpResponse response = client.execute(post);

Обратите внимание, что значение ContentType может быть создано на лету, как в приведенном выше примере для ZIP-файла.

Наконец, не все серверы признают части InputStream. Сервер, который мы создали в первой строке кода, распознает InputStreams.

Давайте теперь посмотрим на другой пример, где addBinaryBody работает напрямую с массивом байтов:

Пример 3.3. — Загрузка массива байтов и текста

HttpPost post = new HttpPost("http://echo.200please.com");
String message = "This is a multipart post";
byte[] bytes = "binary code".getBytes(); 
// 
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
builder.addBinaryBody("upfile", bytes, ContentType.DEFAULT_BINARY, textFileName);
builder.addTextBody("text", message, ContentType.TEXT_PLAIN);
// 
HttpEntity entity = builder.build();
post.setEntity(entity);
HttpResponse response = client.execute(post);

Обратите внимание на ContentType, который теперь определяет двоичные данные.

4. Заключение

В этой статье MultipartEntityBuilder представлен как гибкий объект, который предлагает несколько вариантов API для создания составной формы.

В примерах также показано, как использовать HttpClient для загрузки объекта HttpEntity, похожего на объект формы.

Реализацию всех этих примеров и фрагментов кода можно найти в нашем проекте GitHub — это проект на основе Eclipse, поэтому его должно быть легко импортировать и запускать как есть.