Зробіть простий HTTP-запит на Java

1. Огляд

У цьому короткому підручнику ми представляємо спосіб виконання HTTP-запитів на Java - за допомогою вбудованого Java-класу HttpUrlConnection.

Зверніть увагу , що починаючи з JDK 11, Java надає новий API для виконання HTTP - запитів, який призначений в якості заміни для HttpURLConnection, HttpClient API.

2. HttpUrlConnection

Клас HttpUrlConnection дозволяє нам виконувати основні HTTP-запити без використання додаткових бібліотек. Усі необхідні нам класи є частиною пакету java.net .

Недоліками використання цього методу є те, що код може бути більш громіздким, ніж інші бібліотеки HTTP, і що він не забезпечує більш досконалих функціональних можливостей, таких як виділені методи для додавання заголовків або автентифікації.

3. Створення запиту

Ми можемо створити екземпляр HttpUrlConnection, використовуючи метод openConnection () класу URL . Зверніть увагу, що цей метод створює лише об’єкт підключення, але ще не встановлює зв’язок.

Клас HttpUrlConnection використовується для всіх типів запитів шляхом встановлення атрибуту requestMethod одного із значень: GET, POST, HEAD, OPTIONS, PUT, DELETE, TRACE.

Давайте створимо підключення до заданої URL-адреси методом GET:

URL url = new URL("//example.com"); HttpURLConnection con = (HttpURLConnection) url.openConnection(); con.setRequestMethod("GET");

4. Додавання параметрів запиту

Якщо ми хочемо , щоб додати параметри запиту, ми повинні встановити doOutput властивість вірно , то написати рядок виду param1 = value¶m2 = значення в OutputStream в HttpURLConnection наприклад:

Map parameters = new HashMap(); parameters.put("param1", "val"); con.setDoOutput(true); DataOutputStream out = new DataOutputStream(con.getOutputStream()); out.writeBytes(ParameterStringBuilder.getParamsString(parameters)); out.flush(); out.close();

Для полегшення перетворення карти параметрів ми написали клас утиліти ParameterStringBuilder, що містить статичний метод getParamsString () , який перетворює карту у рядок необхідного формату:

public class ParameterStringBuilder { public static String getParamsString(Map params) throws UnsupportedEncodingException{ StringBuilder result = new StringBuilder(); for (Map.Entry entry : params.entrySet()) { result.append(URLEncoder.encode(entry.getKey(), "UTF-8")); result.append("="); result.append(URLEncoder.encode(entry.getValue(), "UTF-8")); result.append("&"); } String resultString = result.toString(); return resultString.length() > 0 ? resultString.substring(0, resultString.length() - 1) : resultString; } }

5. Встановлення заголовків запитів

Додавання заголовків до запиту можна досягти за допомогою методу setRequestProperty () :

con.setRequestProperty("Content-Type", "application/json");

Щоб прочитати значення заголовка з підключення, ми можемо використовувати метод getHeaderField () :

String contentType = con.getHeaderField("Content-Type");

6. Налаштування часу очікування

Клас HttpUrlConnection дозволяє встановити час очікування підключення та читання. Ці значення визначають інтервал часу очікування встановлення з'єднання із сервером або даних, доступних для читання.

Щоб встановити значення часу очікування, ми можемо використовувати методи setConnectTimeout () та setReadTimeout () :

con.setConnectTimeout(5000); con.setReadTimeout(5000);

У прикладі ми встановлюємо обидва значення часу очікування по п’ять секунд.

7. Поводження з печивом

Пакет java.net містить класи, що полегшують роботу з файлами cookie, такими як CookieManager та HttpCookie .

По-перше, щоб прочитати файли cookie з відповіді , ми можемо отримати значення заголовка Set-Cookie і проаналізувати його до списку об'єктів HttpCookie :

String cookiesHeader = con.getHeaderField("Set-Cookie"); List cookies = HttpCookie.parse(cookiesHeader);

Далі ми додамо файли cookie до магазину печива :

cookies.forEach(cookie -> cookieManager.getCookieStore().add(null, cookie));

Давайте перевіримо, чи присутній файл cookie з іменем користувача , а якщо ні, то додамо його до сховища зі значенням “john”:

Optional usernameCookie = cookies.stream() .findAny().filter(cookie -> cookie.getName().equals("username")); if (usernameCookie == null) { cookieManager.getCookieStore().add(null, new HttpCookie("username", "john")); }

Нарешті, щоб додати файли cookie до запиту , нам потрібно встановити заголовок Cookie , після закриття та повторного відкриття з'єднання:

con.disconnect(); con = (HttpURLConnection) url.openConnection(); con.setRequestProperty("Cookie", StringUtils.join(cookieManager.getCookieStore().getCookies(), ";"));

8. Обробка переадресацій

Ми можемо ввімкнути або вимкнути автоматичне переспрямування для певного підключення за допомогою методу setInstanceFollowRedirects () із параметром true або false :

con.setInstanceFollowRedirects(false);

Також можна ввімкнути або вимкнути автоматичне перенаправлення для всіх підключень :

HttpUrlConnection.setFollowRedirects(false);

За замовчуванням поведінку ввімкнено.

Коли запит повертає код стану 301 або 302, що вказує на переспрямування, ми можемо отримати заголовок Розташування та створити новий запит до нової URL-адреси:

if (status == HttpURLConnection.HTTP_MOVED_TEMP || status == HttpURLConnection.HTTP_MOVED_PERM) { String location = con.getHeaderField("Location"); URL newUrl = new URL(location); con = (HttpURLConnection) newUrl.openConnection(); }

9. Читання відповіді

Читання відповідь на запит може бути зроблено шляхом розбору InputStream в HttpURLConnection інстанції.

Щоб виконати запит, ми можемо використовувати getResponseCode () , підключити () , getInputStream () або getOutputStream () методи :

int status = con.getResponseCode();

Нарешті, прочитаємо відповідь на запит і розмістимо його у рядку вмісту :

BufferedReader in = new BufferedReader( new InputStreamReader(con.getInputStream())); String inputLine; StringBuffer content = new StringBuffer(); while ((inputLine = in.readLine()) != null) { content.append(inputLine); } in.close();

Щоб закрити підключення , ми можемо скористатися методом disconnect () :

con.disconnect(); 

10. Читання відповіді на невдалі запити

Якщо запит не вдається, намагається прочитати InputStream з HttpURLConnection примірника не буде працювати. Натомість ми можемо споживати потік, наданий HttpUrlConnection.getErrorStream () .

Ми можемо вирішити, який InputStream використовувати, порівнюючи код стану HTTP:

int status = con.getResponseCode(); Reader streamReader = null; if (status > 299) { streamReader = new InputStreamReader(con.getErrorStream()); } else { streamReader = new InputStreamReader(con.getInputStream()); }

І нарешті, ми можемо прочитати streamReader так само, як і попередній розділ.

11. Побудова повної відповіді

Неможливо отримати представлення повної відповіді за допомогою екземпляра HttpUrlConnection .

Однак ми можемо побудувати його, використовуючи деякі методи, які пропонує екземпляр HttpUrlConnection :

public class FullResponseBuilder { public static String getFullResponse(HttpURLConnection con) throws IOException { StringBuilder fullResponseBuilder = new StringBuilder(); // read status and message // read headers // read response content return fullResponseBuilder.toString(); } }

Тут ми читаємо частини відповідей, включаючи код стану, повідомлення про стан та заголовки, і додаємо їх до екземпляра StringBuilder .

Спочатку додамо інформацію про статус відповіді :

fullResponseBuilder.append(con.getResponseCode()) .append(" ") .append(con.getResponseMessage()) .append("\n");

Далі ми отримаємо заголовки за допомогою getHeaderFields () і додамо кожен з них до нашого StringBuilder у форматі HeaderName: HeaderValues :

con.getHeaderFields().entrySet().stream() .filter(entry -> entry.getKey() != null) .forEach(entry -> { fullResponseBuilder.append(entry.getKey()).append(": "); List headerValues = entry.getValue(); Iterator it = headerValues.iterator(); if (it.hasNext()) { fullResponseBuilder.append(it.next()); while (it.hasNext()) { fullResponseBuilder.append(", ").append(it.next()); } } fullResponseBuilder.append("\n"); });

Нарешті, ми прочитаємо вміст відповіді, як і раніше, і додамо його.

Зверніть увагу, що метод getFullResponse перевірить, чи був запит успішним чи ні, щоб вирішити, чи потрібно використовувати con.getInputStream () або con.getErrorStream () для отримання вмісту запиту.

12. Висновок

У цій статті ми показали, як ми можемо виконувати HTTP-запити за допомогою класу HttpUrlConnection .

Повний вихідний код прикладів можна знайти на GitHub.