1. Обзор
AsyncHttpClient (AHC) – это библиотека , построенная поверх Netty , с целью легкого выполнения HTTP-запросов и асинхронной обработки ответов.
В этой статье мы расскажем, как настроить и использовать HttpClient, как выполнить запрос и обработать ответ с помощью AHC.
2. Настройка
Последнюю версию библиотеки можно найти в репозитории Maven . Мы должны быть осторожны, чтобы использовать зависимость с идентификатором группы org.asynchttpclient , а не с com.ning:
org.asynchttpclient async-http-client 2.2.0
3. Конфигурация HTTP-клиента
Наиболее простым способом получения HttpClient является использование класса Dsl . Статический метод AsyncHttpClient() возвращает объект AsyncHttpClient :
AsyncHttpClient client = Dsl.asyncHttpClient();
Если нам нужна пользовательская конфигурация HTTP-клиента, мы можем построить объект AsyncHttpClient с помощью конструктора DefaultAsyncHttpClientConfig.Строитель :
DefaultAsyncHttpClientConfig.Builder clientBuilder = Dsl.config()
Это дает возможность настроить тайм-ауты, прокси-сервер, сертификаты HTTP и многое другое:
DefaultAsyncHttpClientConfig.Builder clientBuilder = Dsl.config() .setConnectTimeout(500) .setProxyServer(new ProxyServer(...)); AsyncHttpClient client = Dsl.asyncHttpClient(clientBuilder);
После того, как мы настроили и получили экземпляр HTTP-клиента, мы можем повторно использовать его в приложении . Нам не нужно создавать экземпляр для каждого запроса, потому что внутри он создает новые потоки и пулы соединений, что приведет к проблемам с производительностью.
Кроме того, важно отметить, что как только мы закончим использовать клиент, мы должны вызвать метод close () , чтобы предотвратить любые утечки памяти или зависание ресурсов.
4. Создание HTTP-запроса
Существует два метода, с помощью которых мы можем определить HTTP-запрос с помощью AHC:
- связанный
- несвязанный
Нет никакой существенной разницы между двумя типами запросов с точки зрения производительности. Они представляют только два отдельных API, которые мы можем использовать для определения запроса. Связанный запрос привязан к HTTP-клиенту, из которого он был создан, и по умолчанию будет использовать конфигурацию этого конкретного клиента, если не указано иное.
Например, при создании связанного запроса флаг disableUrlEncoding считывается из конфигурации HTTP-клиента, в то время как для несвязанного запроса по умолчанию установлено значение false. Это полезно, поскольку конфигурацию клиента можно изменить без перекомпиляции всего приложения с помощью системных свойств, передаваемых в качестве аргументов виртуальной машины:
java -jar -Dorg.asynchttpclient.disableUrlEncodingForBoundRequests=true
Полный список свойств можно найти в файле ahc-default.properties .
4.1. Связанный запрос
Для создания связанного запроса мы используем вспомогательные методы из класса AsyncHttpClient , которые начинаются с префикса “prepare” . Кроме того, мы можем использовать метод prepareRequest () , который получает уже созданный объект Request .
Например, метод prepare Get() создаст запрос HTTP GET:
BoundRequestBuilder getRequest = client.prepareGet("http://www.baeldung.com");
4.2. Несвязанный запрос
Несвязанный запрос может быть создан с помощью класса RequestBuilder :
Request getRequest = new RequestBuilder(HttpConstants.Methods.GET) .setUrl("http://www.baeldung.com") .build();
или с помощью вспомогательного класса Dsl , который фактически использует RequestBuilder для настройки метода HTTP и URL-адреса запроса:
Request getRequest = Dsl.get("http://www.baeldung.com").build()
5. Выполнение HTTP-запросов
Название библиотеки дает нам подсказку о том, как могут выполняться запросы. AHC поддерживает как синхронные, так и асинхронные запросы.
Выполнение запроса зависит от его типа. При использовании связанного запроса мы используем метод execute() из класса BoundRequestBuilder , а когда у нас есть несвязанный запрос, мы выполним его, используя одну из реализаций метода executeRequest() из интерфейса AsyncHttpClient .
5.1. Синхронно
Библиотека была спроектирована как асинхронная, но при необходимости мы можем имитировать синхронные вызовы, блокируя объект Future . Оба метода execute() и execute Request() возвращают объект |/ListenableFuture|/. Этот класс расширяет интерфейс Java Future , таким образом наследуя метод get () , который может использоваться для блокировки текущего потока до тех пор, пока HTTP-запрос не будет завершен и не вернет ответ:
FutureresponseFuture = boundGetRequest.execute(); responseFuture.get();
FutureresponseFuture = client.executeRequest(unboundRequest); responseFuture.get();
Использование синхронных вызовов полезно при попытке отладки частей нашего кода, но его не рекомендуется использовать в рабочей среде, где асинхронное выполнение приводит к повышению производительности и пропускной способности.
5.2. Асинхронно
Когда мы говорим об асинхронных исполнениях, мы также говорим о прослушивателях для обработки результатов. Библиотека AHC предоставляет 3 типа прослушивателей, которые можно использовать для асинхронных HTTP-вызовов:
- Асинхронный манипулятор
- AsyncCompletionHandler
- ListenableFuture слушатели
Прослушиватель AsyncHandler предоставляет возможность контролировать и обрабатывать HTTP-вызов до его завершения. С его помощью можно обрабатывать ряд событий, связанных с вызовом HTTP:
request.execute(new AsyncHandler
Перечисление State позволяет нам управлять обработкой HTTP-запроса. Возвращением Состояние.ПРЕРВАТЬ мы можем остановить обработку в определенный момент и с помощью Состояния.ПРОДОЛЖИТЬ мы позволяем обработке закончиться.
Важно отметить, что AsyncHandler не является потокобезопасным и не должен повторно использоваться при выполнении параллельных запросов.
AsyncCompletionHandler наследует все методы из интерфейса AsyncHandler и добавляет вспомогательный метод OnCompleted(Response) для обработки завершения вызова. Все остальные методы прослушивателя переопределяются для возврата состояния. ПРОДОЛЖАЙТЕ, тем самым делая код более читабельным:
request.execute(new AsyncCompletionHandler
Интерфейс ListenableFuture позволяет нам добавлять прослушиватели, которые будут запускаться после завершения HTTP-вызова.
Кроме того, он позволяет выполнять код из прослушивателей – с помощью другого пула потоков:
ListenableFuturelistenableFuture = client .executeRequest(unboundRequest); listenableFuture.addListener(() -> { Response response = listenableFuture.get(); LOG.debug(response.getStatusCode()); }, Executors.newCachedThreadPool());
Кроме того, возможность добавления слушателей, интерфейс ListenableFuture позволяет нам преобразовать Будущий ответ в CompletableFuture .
7. Заключение
AHC-это очень мощная библиотека с множеством интересных функций. Он предлагает очень простой способ настройки HTTP-клиента и возможность выполнения как синхронных, так и асинхронных запросов.
Как всегда, исходный код статьи доступен на GitHub .