Сделайте простой 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();

Чтобы облегчить преобразование параметра Map , мы написали служебный класс под названием ParameterStringBuilder, содержащий статический метод getParamsString () , который преобразует Map в строку требуемого формата:

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. Обработка файлов cookie

Пакет java.net содержит классы, упрощающие работу с файлами cookie, например CookieManager и HttpCookie .

Во-первых, чтобы прочитать файлы cookie из ответа , мы можем получить значение заголовка Set-Cookie и преобразовать его в список объектов HttpCookie :

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

Затем мы добавим файлы cookie в хранилище файлов cookie :

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

Давайте проверим, присутствует ли файл cookie с именем username , а если нет, мы добавим его в хранилище файлов 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, указывающий на перенаправление, мы можем получить заголовок 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();

Наконец, давайте прочитаем ответ на запрос и поместим его в строку содержимого :

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 () .

We can decide which InputStream to use by comparing the HTTP status code:

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

And finally, we can read the streamReader in the same way as the previous section.

11. Building the Full Response

It's not possible to get the full response representation using the HttpUrlConnection instance.

However, we can build it using some of the methods that the HttpUrlConnection instance offers:

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(); } }

Here, we're reading the parts of the responses, including the status code, status message and headers, and adding these to a StringBuilder instance.

First, let's add the response status information:

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.