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

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

1. обзор

В этом кратком руководстве мы собираемся представитьway of performing HTTP requests in Java - используя встроенный класс JavaHttpUrlConnection.

Дальнейшее чтение:

Руководство по HTTP-куки в Java

Краткое и практическое руководство по HTTP-куки в Java

Read more

Изучение нового HTTP-клиента в Java 9 и 11

Изучите новый API HttpClient в Java 9, который обеспечивает большую гибкость и мощные функции.

Read more

Веб-серверы и серверы приложений для Java

Быстрый список доступных веб-серверов и серверов приложений на Java.

Read more

2. HttpUrlConnectionс

КлассHttpUrlConnection позволяет намperform basic HTTP requests without the use of any additional libraries. Все необходимые классы содержатся в пакетеjava.net.

Недостатки использования этого метода в том, чтоthe code can be more cumbersome than other HTTP libraries, and it does not provide more advanced functionalities such as dedicated methods for adding headers or authentication.

3. Создание запроса

A HttpUrlConnection instance is created by using the openConnection() method of the URL class. Обратите внимание, что этот метод только создает объект подключения, но еще не устанавливает соединение.

КлассHttpUrlConnection используется для всех типов запросов, устанавливая для атрибутаrequestMethod одно из значений: 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. Добавление параметров запроса

Если мы хотим добавить параметры к запросу, мы должны установить для свойстваdoOutput значениеtrue, а затем записатьString формыparam1=value¶m2=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 Map, мы написали служебный классParameterStringBuilder, содержащий статический методgetParamsString(), который преобразуетMap вString требуемый формат:

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 разрешаетsetting the connect and read timeouts. Эти значения определяют интервал времени ожидания установления соединения с сервером или доступности данных для чтения.

Чтобы установить значения тайм-аута, мы можем использовать методыsetConnectTimeout() иsetReadTimeout():

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

В приведенном выше примере мы установили оба значения времени ожидания на 5 секунд.

7. Обработка печенья

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

Во-первых, дляread the cookies from a response мы можем получить значение заголовкаSet-Cookie и проанализировать его до списка объектовHttpCookie:

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

Далее мы будемadd the cookies to the cookie store:

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

Наконец, дляadd the cookies to the request нам нужно установить заголовокCookie после закрытия и повторного открытия соединения:

con.disconnect();
con = (HttpURLConnection) url.openConnection();

con.setRequestProperty("Cookie",
  StringUtils.join(cookieManager.getCookieStore().getCookies(), ";"));

8. Обработка перенаправлений

Мы можемenable or disable automatically following redirects for a specific connection, используя методsetInstanceFollowRedirects() с параметромtrue илиfalse:

con.setInstanceFollowRedirects(false);

Также возможноenable or disable automatic redirect for all connections:

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. Чтение ответа

Чтение ответа на запрос может быть выполненоparsing the InputStream of the HttpUrlConnection instance.

Для выполнения запроса мы можем использовать методы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();

Дляclose the connection мы можем использовать методdisconnect():

con.disconnect();

10. Чтение ответа на неудавшиеся запросы

В случае сбоя запроса попытка чтенияInputStream экземпляраHttpUrlConnection не сработает. Вместо этогоwe can consume the stream provided by 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 .

Однако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();
    }
}

Здесь мы читаем части ответов, включая код состояния, сообщение о состоянии и заголовки, и добавляем их в экземплярStringBuilder.

Во-первых, давайте добавим информацию о статусе ответа:

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

Next, we’ll get the headers using 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");
});

Finally, we’ll read the response content, как мы делали ранее, и добавляем его.

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

12. Заключение

В этой статье мы показали, как мы можем выполнять HTTP-запросы, используя классHttpUrlConnection. Полный исходный код примеров можно найти наover on GitHub.