Рубрики
Без рубрики

Сделайте простой HTTP-запрос на Java

Краткое и практическое руководство по выполнению основных HTTP-запросов с использованием встроенного в Java HttpURLConnection.

Автор оригинала: baeldung.

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&param2=value в 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();

Чтобы облегчить преобразование карты параметров , мы написали служебный класс под названием Parameter StringBuilder , содержащий статический метод 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. Обработка файлов Cookie

В java.net пакет содержит классы, облегчающие работу с файлами cookie, такими как Cookie Manager и Http Cookie .

Во-первых, чтобы прочитать файлы 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();

Наконец, давайте прочитаем ответ на запрос и поместим его в строку 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 .