1. Обзор
В этом кратком руководстве мы представляем способ выполнения HTTP — запросов в Java -с помощью встроенного класса Java HttpURLConnection.
Обратите внимание, что начиная с JDK 11, Java предоставляет новый API для выполнения HTTP-запросов, который предназначен для замены HttpURLConnection, API HttpClient|/.
Дальнейшее чтение:
Руководство По HTTP-Файлам Cookie На Java
Изучение нового HTTP-клиента на Java
Веб-серверы и серверы приложений для Java
2. HttpURLConnection
Класс HttpURLConnection позволяет нам выполнять базовые HTTP-запросы без использования каких-либо дополнительных библиотек. Все классы, которые нам нужны, являются частью java.net пакет.
Недостатки использования этого метода заключаются в том, что код может быть более громоздким, чем другие библиотеки HTTP, и что он не предоставляет более продвинутых функций, таких как специальные методы добавления заголовков или аутентификации.
3. Создание запроса
Мы можем создать экземпляр HttpURLConnection , используя метод openConnection() класса URL . Обратите внимание, что этот метод только создает объект соединения, но еще не устанавливает соединение.
Класс HttpURLConnection используется для всех типов запросов путем установки атрибута request Method в одно из значений: GET, POST, HEAD, OPTIONS, PUT, DELETE, TRACE.
Давайте создадим соединение с заданным URL – адресом с помощью метода GET:
URL url = new URL("http://example.com"); HttpURLConnection con = (HttpURLConnection) url.openConnection(); con.setRequestMethod("GET");
4. Добавление Параметров Запроса
Если мы хотим добавить параметры в запрос, мы должны установить свойство output в true , а затем записать Строку формы param1=value¶m2=value в OutputStream экземпляра HttpURLConnection :
Mapparameters = new HashMap<>(); parameters.put("param1", "val"); con.setDoOutput(true); DataOutputStream out = new DataOutputStream(con.getOutputStream()); out.writeBytes(ParameterStringBuilder.getParamsString(parameters)); out.flush(); out.close();
Чтобы облегчить преобразование карты параметров , мы написали служебный класс под названием Parameter StringBuilder , содержащий статический метод getParamsString() , который преобразует Карту в Строку требуемого формата:
public class ParameterStringBuilder { public static String getParamsString(Mapparams) 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. Обработка файлов Cookie
В java.net пакет содержит классы, облегчающие работу с файлами cookie, такими как Cookie Manager и Http Cookie .
Во-первых, чтобы прочитать файлы cookie из ответа , мы можем получить значение заголовка Set-Cookie и проанализировать его в список объектов HttpCookie :
String cookiesHeader = con.getHeaderField("Set-Cookie"); Listcookies = HttpCookie.parse(cookiesHeader);
Затем мы добавим файлы cookie в хранилище файлов cookie :
cookies.forEach(cookie -> cookieManager.getCookieStore().add(null, cookie));
Давайте проверим, присутствует ли файл cookie с именем username , и если нет, мы добавим его в хранилище файлов cookie со значением “john”:
OptionalusernameCookie = 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, указывающий на перенаправление, мы можем получить заголовок Location и создать новый запрос на новый 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 () , connect() , getInputStream() или getOutputStream() методы :
int status = con.getResponseCode();
Наконец, давайте прочитаем ответ на запрос и поместим его в строку content :
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"); });
Наконец, мы прочитаем содержимое ответа , как мы делали это ранее, и добавим его.
Обратите внимание, что метод get Full Response проверит, был ли запрос успешным или нет, чтобы решить, нужно ли использовать con.getInputStream() или con.getErrorStream() для извлечения содержимого запроса.
12. Заключение
В этой статье мы показали, как мы можем выполнять HTTP-запросы с помощью класса HttpURLConnection .
Полный исходный код примеров можно найти на GitHub .