JavaRush /Курсы /JSP & Servlets /Выполнение запроса с помощью HttpClient

Выполнение запроса с помощью HttpClient

JSP & Servlets
10 уровень , 3 лекция
Открыта

4.1 Метод send(), BodyHandlers

Ты закончил изучать, как формировать http-запрос, значит можно переходить к самому главному – отправке этого запроса. В самом простом случае это сделать легко:


HttpRequest request = HttpRequest.newBuilder(new URI("https://javarush.com")).build();
 
   HttpClient client = HttpClient.newBuilder()
        .version(Version.HTTP_1_1)
        .build();
 
   HttpResponse<String> response = client.send(request, BodyHandlers.ofString());
   System.out.println(response.statusCode() );
   System.out.println(response.body() ); 

А что это за BodyHandlers такие? А как ты думаешь? Ты отправил запрос, а значит вам должен прийти ответ – http response. И у этого ответа может быть response body: строка, файл, массив байт, InputStream.

Да, да, все верно. Так же, как и при формировании запроса, тебе нужно указать тип response body у ответа. Всего их может быть 8 штук:

  • BodyHandlers.ofByteArray
  • BodyHandlers.ofString
  • BodyHandlers.ofFile
  • BodyHandlers.discarding
  • BodyHandlers.replacing
  • BodyHandlers.ofLines
  • BodyHandlers.fromLineSubscriber

В зависимости от того, какой тип BodyHandlers ты передал в метод send(), такой тип результата он и вернет. Пример:


   // response body игнорируется
   HttpResponse<Void> response = client.send(request, BodyHandlers.discarding()); 

  // response body это строка
   HttpResponse<String>response = client.send(request, BodyHandlers.ofString());
 

   // response body это файл
   HttpResponse<Path> response = client.send(request, BodyHandlers.ofFile(Paths.get("readme.txt")));

   // response body это InputStream
   HttpResponse<InputStream> response = client.send(request, BodyHandlers.ofInputStream());

Если в качестве ответа тебе должны прислать файл, то в метод BodyHandlers.ofFile() тебе нужно передать имя локального файла, куда он будет сохранен объектом HttpClient.

4.2 Метод followRedirects()

Также при отправке запроса ты можешь указать, что делать HttpClient’у, если сервер в ответ пришлет 301 или 302 (временный или постоянный редирект). Представь, что сервер прислал код 302, и тебе нужно: отследить эту ситуацию, получить новый URL из ответа и отправить запрос по новому адресу.

Не сильно бы хотелось таким заниматься, особенно учитывая, что эта ситуация встречается часто и уже давно автоматизирована во всех http-клиентах. Также и в этом HttpClient’е тебе нужно просто указать какой режим редиректа ты выбираешь при отправке запроса.


HttpResponse
      
  
      
  
      
  
    response = HttpClient.newBuilder() 
    .followRedirects( HttpClient.Redirect.ALWAYS ) .build() .send(request, BodyHandlers.ofString()); 
  

Есть всего 3 варианта для редиректа:

  • ALWAYS – всегда;
  • NEVER – никогда;
  • NORMAL – всегда, кроме HTTPS -> HTTP.

Как видишь, вариантов тут немного, но всегда лучше иметь возможность настройки, чем не иметь ее.

4.3 Метод proxy()

Есть еще пара полезных, но не часто используемых опций. Они тебе не нужны ровно до тех пор, пока не станут нужны :)

Первый – это proxy. В обычной жизни ты не часто сталкиваешься с ними, но многие крупные корпорации имеют у себя внутри сложную систему безопасности интернет-трафика, а значит и различные настройки proxy.

Ну, и конечно, твой софт, который будет работать где-то в недрах такой корпорации когда-то столкнется с тем, что ему нужно будет задействовать proxy. Поэтому хорошо, что такая опция тут тоже есть.

Настроить прокси очень просто – пример:


HttpResponse<String> response = HttpClient.newBuilder()
 .proxy( ProxySelector.getDefault())
  .build()
  .send(request, BodyHandlers.ofString());

Тут был выбран proxy по умолчанию, но ты можешь захотеть настроить свой:


HttpResponse
      
  
      
  
      
  
    response = HttpClient.newBuilder() 
    .proxy(ProxySelector.of( 
   new InetSocketAddress("proxy.microsoft.com", 80) 
   )) .build() .send(request, BodyHandlers.ofString()); 
  

Как именно работать с proxy мы рассматривать не будем, так как это не входит в рамки данного курса.

4.4 authenticator()

И еще один важный момент. HTTP-протокол поддерживает аутентификацию. Прямо на уровне протокола.

Сейчас таким подходом почти не пользуются, но лет 20 назад он был распространен. Выглядел такой Http-запрос так:


        http://username@example.com/
        

Или даже так:


        http://username:password@example.com/
        

Это не почта. Это именно ссылка. И да, тебе не показалось. Логин и даже пароль можно было указать прямо в http-запросе. Да и сейчас можно. Поэтому я и пишу, что сейчас так обычно никто не делает. Но такая возможность есть.


Authenticator auth = new Authenticator() {
    @Override
    protected PasswordAuthentication getPasswordAuthentication() {
    return new PasswordAuthentication(
     "username",
        "password".toCharArray());
    }
};
 
HttpResponse<String> response = HttpClient.newBuilder()
  .authenticator(auth).build()
  .send(request, BodyHandlers.ofString());

Это интересно! Знаете почему вместо “password" в коде написано "password".toCharArray() ?

Потому что второй параметр конструктора PasswordAuthentication – не String, а CharArray.

А почему второй параметр не String, а CharArray?

Потому что все пароли в целях безопасности запрещается хранить в виде целой строки даже в своем собственном приложении. То есть ваше приложение в своей памяти не должно хранить пароль в виде строки. Чтобы если кто-то сделал damp-памяти, из него нельзя было вытащить пароль…

Но при этом пароль можно передать по незащищенному HTTP-протоколу через полмира :) :) :)

Что ж. Мир не идеален.

Более детально ты можешь ознакомиться с этой темой по ссылкам:

HTTP аутентификация

Understanding HTTP Authentication

Комментарии (12)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Дмитрий Уровень 111 Expert
27 сентября 2023
В списке BodyHandlers восьмой пункт забыли. BodyHandlers.ofInputStream() потерялся.
Dima Makarov Уровень 42
22 августа 2023
Вот кто-то мне скажет секрет, как можно это все знать? Я уже читая конец статьи слабо помню, что там было в начале. Как все это впихнуть в голову - не представляю
PHANTOM Уровень 42 Expert
7 сентября 2023
Секрет просто на самом деле. Ты это будешь знать, помнить и понимать тогда, когда будешь этим пользоваться. Пока просто ознакомься. И в следующий раз когда ты сюда вернешься, тебя уже не будут пугать такие слова как HTTP, REST и т.д. Перечитаешь еще раз, более осмысленно
Виталий Уровень 107 Expert
16 сентября 2023
Не обязательно прям знать все, но нужно знать, что тебе нужно чтобы ты хотя бы загуглить это мог
Anonymous #3268884 Уровень 24
2 апреля 2024
Если систематизировать информацию, то окажется, что запомнить надо не так и много. Для отсылки запроса и получения ответа используется всего три класса с подклассами и в общей сложности пара-тройка десятков методов. Итого: методы класса HttpRequest: методы в подклассе Builder: uri( ) version( ) header( ) / headers( ) timeout( ) GET( ) / PUT( ) / POST( ) / DELETE( ) методы в подклассе BodyPublishers: ofByteArray( ) ofString( ) ofFile( ) discarding( ) replacing( ) ofLines( ) fromLineSubscriber( ) ofInputStream( ) методы класса HttpClient: методы в подклассе Builder: version( ) followRedirects( ) connectTimeout( ) proxy( ) authenticator( ) executor( ) основные методы: send( ) sendAsync( ) cookieHandler( ) методы класса HttpResponse: основные методы: body() headers() statusCode() uri() методы в подклассе BodyHandlers: такие же, как в BodyPublishers Вот практически и вся тема
Rolik Уровень 41
15 августа 2023
Сейчас этим подходом уже никто не пользуется, но лет 20 назад ... Зачем грузить голову тем что было 20 лет назад ??
Dima Makarov Уровень 42
14 сентября 2023
Вероятно потому, что JAVA старая как мамонт и еще не редко можно встретить софт который написан был как раз таки 20 лет назад.
Andrey Panchenko Уровень 26
17 сентября 2022
Ох попа будет гореть у кого-то на Spring Security без знаний AAA.
jvatechs Уровень 111 Expert
14 июня 2023
а что за знания ААА?
Anonymous #3278550 Уровень 1
10 августа 2023
Authentication (Аутентификация): Это процесс проверки подлинности субъекта (пользователя, устройства и т. д.) для установления его идентичности. В случае Spring Security, это означает проверку, что пользователь является тем, за кого он себя выдаёт. Authorization (Авторизация): Это процесс управления доступом субъектов к ресурсам или функциональности системы на основе их идентичности и прав. В случае Spring Security, это означает определение, к каким ресурсам и действиям пользователь имеет доступ. Accounting (Учёт): Это процесс регистрации и отслеживания действий субъектов, которые взаимодействуют с системой. Это может включать в себя запись аудиторских данных, следящих за действиями пользователей.
jvatechs Уровень 111 Expert
10 августа 2023
Спасибо, информативно
Павел Уровень 19 Expert
27 декабря 2023
Выглядит как ответ из будущего. Неужели java в какой-то версии и до этого дойдет?¿