«1. Обзор

В этом руководстве — мы проведем POST с помощью HttpClient 4 — используя сначала авторизацию, а затем свободный HttpClient API.

Наконец, мы обсудим, как загрузить файл с помощью Httpclient.

2. Базовый POST

Сначала давайте рассмотрим простой пример и отправим запрос POST с помощью HttpClient.

Мы выполним POST с двумя параметрами — «username» и «password»:

Обратите внимание, как мы использовали List of NameValuePair для включения параметров в запрос POST.

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

    List<NameValuePair> params = new ArrayList<NameValuePair>();
    params.add(new BasicNameValuePair("username", "John"));
    params.add(new BasicNameValuePair("password", "pass"));
    httpPost.setEntity(new UrlEncodedFormEntity(params));

    CloseableHttpResponse response = client.execute(httpPost);
    assertThat(response.getStatusLine().getStatusCode(), equalTo(200));
    client.close();
}

3. POST с авторизацией

Далее давайте посмотрим, как выполнить POST с учетными данными аутентификации с помощью HttpClient.

В следующем примере мы отправляем запрос POST на URL-адрес, защищенный базовой аутентификацией, добавляя заголовок Authorization:

4. POST с JSON

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

    httpPost.setEntity(new StringEntity("test post"));
    UsernamePasswordCredentials creds
      = new UsernamePasswordCredentials("John", "pass");
    httpPost.addHeader(new BasicScheme().authenticate(creds, httpPost, null));

    CloseableHttpResponse response = client.execute(httpPost);
    assertThat(response.getStatusLine().getStatusCode(), equalTo(200));
    client.close();
}

Теперь – давайте посмотрим, как отправьте запрос POST с телом JSON с помощью HttpClient.

В следующем примере мы отправляем некоторую информацию о человеке (идентификатор, имя) в виде JSON:

Обратите внимание, как мы используем StringEntity для установки тела запроса.

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

    String json = "{"id":1,"name":"John"}";
    StringEntity entity = new StringEntity(json);
    httpPost.setEntity(entity);
    httpPost.setHeader("Accept", "application/json");
    httpPost.setHeader("Content-type", "application/json");

    CloseableHttpResponse response = client.execute(httpPost);
    assertThat(response.getStatusLine().getStatusCode(), equalTo(200));
    client.close();
}

Мы также устанавливаем заголовок ContentType в application/json, чтобы предоставить серверу необходимую информацию о представлении контента, который мы отправляем.

5. POST с помощью HttpClient Fluent API

Далее, давайте отправим POST с помощью HttpClient Fluent API.

Мы собираемся отправить запрос с двумя параметрами «имя пользователя» и «пароль»:

6. POST составной запрос

@Test
public void whenPostFormUsingHttpClientFluentAPI_thenCorrect() 
  throws ClientProtocolException, IOException {
    HttpResponse response = Request.Post("http://www.example.com").bodyForm(
      Form.form().add("username", "John").add("password", "pass").build())
      .execute().returnResponse();

    assertThat(response.getStatusLine().getStatusCode(), equalTo(200));
}

Теперь давайте отправим составной запрос.

Мы отправим файл, имя пользователя и пароль с помощью MultipartEntityBuilder:

7. Загрузите файл с помощью HttpClient

@Test
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);
    assertThat(response.getStatusLine().getStatusCode(), equalTo(200));
    client.close();
}

Далее давайте посмотрим, как загрузить файл с помощью HttpClient.

Мы загрузим файл «test.txt» с помощью MultipartEntityBuilder:

8. Получение хода загрузки файла

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

    MultipartEntityBuilder builder = MultipartEntityBuilder.create();
    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);
    assertThat(response.getStatusLine().getStatusCode(), equalTo(200));
    client.close();
}

Наконец, давайте посмотрим, как получить ход загрузки файла с помощью HttpClient.

В следующем примере мы расширим HttpEntityWrapper, чтобы получить представление о процессе загрузки.

Сначала — вот метод загрузки:

Мы также добавим интерфейс ProgressListener, который позволит нам наблюдать за ходом загрузки:

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

    MultipartEntityBuilder builder = MultipartEntityBuilder.create();
    builder.addBinaryBody(
      "file", new File("test.txt"), ContentType.APPLICATION_OCTET_STREAM, "file.ext");
    HttpEntity multipart = builder.build();

    ProgressEntityWrapper.ProgressListener pListener = 
      percentage -> assertFalse(Float.compare(percentage, 100) > 0);
    httpPost.setEntity(new ProgressEntityWrapper(multipart, pListener));

    CloseableHttpResponse response = client.execute(httpPost);
    assertThat(response.getStatusLine().getStatusCode(), equalTo(200));
    client.close();
}

А вот и наша расширенная версия HttpEntityWrapper — «ProgressEntityWrapper»:

public static interface ProgressListener {
    void progress(float percentage);
}

И расширенная версия FilterOutputStream «CountingOutputStream»:

public class ProgressEntityWrapper extends HttpEntityWrapper {
    private ProgressListener listener;

    public ProgressEntityWrapper(HttpEntity entity, ProgressListener listener) {
        super(entity);
        this.listener = listener;
    }

    @Override
    public void writeTo(OutputStream outstream) throws IOException {
        super.writeTo(new CountingOutputStream(outstream, listener, getContentLength()));
    }
}

Обратите внимание, что:

public static class CountingOutputStream extends FilterOutputStream {
    private ProgressListener listener;
    private long transferred;
    private long totalBytes;

    public CountingOutputStream(
      OutputStream out, ProgressListener listener, long totalBytes) {
        super(out);
        this.listener = listener;
        transferred = 0;
        this.totalBytes = totalBytes;
    }

    @Override
    public void write(byte[] b, int off, int len) throws IOException {
        out.write(b, off, len);
        transferred += len;
        listener.progress(getCurrentProgress());
    }

    @Override
    public void write(int b) throws IOException {
        out.write(b);
        transferred++;
        listener.progress(getCurrentProgress());
    }

    private float getCurrentProgress() {
        return ((float) transferred / totalBytes) * 100;
    }
}

При расширении FilterOutputStream до «CountingOutputStream» — мы переопределяем запись () для подсчета записанных (переданных) байтов При расширении HttpEntityWrapper до «ProgressEntityWrapper» — мы переопределяем метод writeTo() для использования нашего «CountingOutputStream»

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

В этом руководстве мы проиллюстрировали наиболее распространенные способы отправки POST-запросов HTTP с помощью Apache HttpClient 4.

Мы узнали, как отправлять POST-запросы с авторизацией, как публиковать с помощью HttpClient Fluent API и как загружать файл и отслеживать его ход.

Реализацию всех этих примеров и фрагментов кода можно найти в проекте github.

«