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.
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.
Як бачиш, варіантів тут небагато, але завжди краще мати можливість налаштування, аніж не мати її.
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. 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-протоколу через півсвіту :)
Що ж. Світ не є ідеальним.
Детальніше з цією темою ти можеш ознайомитися за посиланнями: