Краткое руководство по HTTP-клиенту Java

Изучив это руководство, вы узнаете, как использовать HTTP-клиент Java для выполнения запросов и его основные функции. HTTP-клиент был представлен в Java 11 (сентябрь 2018 г.) с целью предложить разработчикам более простой способ выполнения HTTP-запросов. Ранее доступный HttpURLConnectionAPI был многословным, сложным и устаревшим. Новый API имеет множество полезных функций, поддерживает синхронное и асинхронное программирование, а также совместим с HTTP/1.1 и HTTP/2.

Выполнение основного запроса

Пример выполнения GET-запроса:

HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://example.com/"))
                .build();
HttpResponse<String> response = client.send(request, BodyHandlers.ofString());
System.out.println("response body: " + response.body());
В этом примере HTTP-клиент основан на классах HttpClient, HttpRequest и HttpResponse.

Создание HttpClient

Для выполнения запроса HttpClient необходим экземпляр. Существует два статических метода для его получения.
  1. HttpClient.newHttpClient() создает значение по умолчанию HttpClient, которое подходит для большинства случаев.
  2. HttpClient.newBuilder() возвращает построитель (билдер, builder) для более конкретных настроек, таких как версия HTTP, политика перенаправления, прокси-сервер, CookieHandler, HTTP-аутентификация и многое другое.

HttpClient client = HttpClient.newBuilder()
        .followRedirects(Redirect.NORMAL)
        .build();

Создание HttpRequest

Запрос, который необходимо выполнить, представлен классом HttpRequest. Он создается построителем запросов, и с его помощью мы определяем URI, метод запроса, тело, заголовки, время ожидания запроса и версию HTTP. Метод HttpRequest.newBuilder() создает построитель (билдер). В качестве альтернативы есть вариант HttpRequest.newBuilder(URI uri), который уже принимает URI для более короткого кода.

Настройка заголовка запроса

Заголовок можно настроить с помощью header(String name, String value) метода построителя запросов.

HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create("https://example.com/api/products"))
        .header("Authorization", "Bearer 6f0e91f1-b237-45dc-a462-5b6bd1bf9747")
        .build();

Настройка метода HTTP и тела запроса

Для настройки метода HTTP для запроса в билдере есть методы с эквивалентным названием: GET, POST, PUT и DELETE. Тело запроса передается как параметр в файле BodyPublisher. Для создания экземпляра BodyPublisher у класса BodyPublishers есть статические методы, такие как ofString(String body), ofByteArray(byte[] buf) и другие. Также есть статический метод noBody() для выполнения запроса без тела.

HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create("https://example.com/api/products"))
        .header("Content-Type", "application/json")
        .POST(BodyPublishers.ofString("{\"message\": \"Test.\"}"))
        .build();
У построителя также есть method(String method, BodyPublisher bodyPublisher), который принимает имя метода HTTP как String.

HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create("https://example.com/api/products/1"))
        .header("Content-Type", "application/json")
        .method("POST", BodyPublishers.ofString("{\"message\": \"Test.\"}"))
        .build();

Время ожидания запроса

У построителя HttpRequest есть метод timeout, который принимает показатель времени в виде файла java.time.Duration. Время можно получить такими методами, как Duration.ofMinutes(2) и Duration.ofSeconds(45). Если время ожидания истекло до получения ответа, то используется HttpTimeoutException.

HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create("https://example.com/api/products"))
        .timeout(Duration.ofMinutes(2))
        .build();
Учтите, что без установки тайм-аута клиент будет бесконечно ждать ответа.

Реализации BodyHandler

BodyHandler — это интерфейс, который определяет, как будет управляться тело ответа на запрос. Методы HttpClient, выполняющие запросы, принимают файл BodyHandler. Класс BodyHandlers имеет статические методы, которые предлагают BodyHandler такие реализации, как ofString(), ofByteArray(), ofInputStream() и другие.

HttpResponse<String> response1 = client.send(request, HttpResponse.BodyHandlers.ofString());
HttpResponse<byte[]> response2 = client.send(request, HttpResponse.BodyHandlers.ofByteArray());

Асинхронный запрос

HttpClient имеет метод sendAsync(HttpRequest request, BodyHandler<T> responseBodyHandler), который возвращает CompletableFuture и выполняет запрос асинхронно. CompletableFuture — это класс, предназначенный для асинхронного программирования. Он представляет собой результат операции, выполняемой асинхронно, и предлагает полезные методы для обработки успешных результатов и ошибок.

HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder(URI.create("https://example.com/api/products")).build();
CompletableFuture<HttpResponse<String>> future = client.sendAsync(request, BodyHandlers.ofString());
future.thenAccept(response -> System.out.println("response body: " + response.body()));
Метод thenAccept(Consumer<? super T> action) выполнит полученный Consumer после успешного завершения запроса.

HttpResponse

HttpResponse возвращается при отправке запроса и имеет методы для получения кода состояния ответа, тела и заголовков, а также данных запроса.

HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder(URI.create("https://example.com/")).build();
HttpResponse<String> response = client.send(request, BodyHandlers.ofString());
System.out.println("status code: " + response.statusCode());
System.out.println("headers: " + response.headers());
System.out.println("response body: " + response.body());

Более короткий код со статическим импортом

HTTP-клиент намного проще, чем старые классы и методы, но на самом деле он все еще многословен. И при частом использовании, например, в тестовом коде endpoint, проблема усугубляется. Однако код все же можно сделать более кратким, используя статический импорт.

var response = newHttpClient().send(newBuilder(URI.create("https://example.com/api/products")).build(),
        BodyHandlers.ofString());
System.out.println("response body: " + response.body());

Заключение

В этом руководстве мы узнали, как использовать HTTP-клиент Java для выполнения запросов, а также его основные функции.