W3docs

Java HttpURLConnection

Отправляйте HTTP-запросы в Java с помощью устаревшего API HttpURLConnection.

HttpURLConnection — это HTTP-осведомлённый подкласс URLConnection. Когда вы вызываете openConnection() на URL с протоколом http: или https:, возвращаемый объект является HttpURLConnection — приведите его к этому типу, чтобы получить доступ к HTTP-специфичным возможностям: установке метода запроса, чтению кода статуса и обращению к отдельному потоку ошибок. Это оригинальный HTTP-клиент JDK, доступный начиная с Java 1.1.

В этой главе рассматривается приведение типа соединения и выбор метода, отправка тела запроса, код статуса и два потока ответа (классическая ловушка с потоком ошибок), а также полный пример POST-запроса, который можно запустить.

Современная альтернатива: для нового кода предпочитайте java.net.http.HttpClient — он чище, поддерживает HTTP/2 и асинхронную работу. HttpURLConnection по-прежнему широко используется в старых кодовых базах, поэтому его стоит хорошо знать.

Приведение типа и выбор метода

URL url = URI.create("http://example.com/api").toURL();
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");                       // GET is the default
conn.setRequestProperty("Content-Type", "application/json");
conn.setConnectTimeout(2000);
conn.setReadTimeout(2000);

setRequestMethod принимает значения "GET", "POST", "PUT", "DELETE" и т.д. Заголовки запроса добавляются с помощью setRequestProperty.

Отправка тела запроса

Чтобы отправить тело, необходимо явно включить эту возможность с помощью setDoOutput(true) (что также меняет метод по умолчанию на POST), а затем записать данные в выходной поток:

conn.setDoOutput(true);
try (OutputStream os = conn.getOutputStream()) {
    os.write(payload.getBytes(StandardCharsets.UTF_8));
}

Код статуса и два потока

Ключевой HTTP-особенностью является код статуса, и вытекающая из него ловушка:

int code = conn.getResponseCode();          // triggers the request
InputStream body = (code >= 200 && code < 400)
        ? conn.getInputStream()             // success body
        : conn.getErrorStream();            // error body (4xx/5xx)

getInputStream() выбрасывает IOException при ответе 4xx/5xx. Тело ошибки находится в другом потоке — getErrorStream(). Забыть об этом — классическая ошибка при работе с HttpURLConnection: ответ с ошибкой приводит к исключению вместо того, чтобы позволить прочитать объяснение сервера. Всегда сначала проверяйте getResponseCode(). Завершайте работу вызовом conn.disconnect().

Пример: полный POST-запрос

Эта программа запускает loopback-сервер, который отражает тело запроса обратно с кодом 201 Created, а затем выполняет POST через HttpURLConnection: устанавливает метод, записывает тело, читает статус и выбирает правильный поток.

java— editable, runs on the server

Что следует вынести из запуска:

  • Приведение URLConnection к HttpURLConnection открыло доступ к HTTP-уровню: setRequestMethod("POST"), getResponseCode() и getResponseMessage() существуют только в подклассе. Для URL с протоколом http: объект действительно является HttpURLConnection, поэтому приведение всегда успешно.
  • Для отправки тела потребовалось вызвать setDoOutput(true) перед записью в getOutputStream(). Без этого вызова соединение остаётся только для чтения и запись завершится ошибкой — включение вывода — это переключатель, превращающий GET в запрос с телом.
  • getResponseCode() вернул 201 и именно он фактически отправил запрос на сервер. Код статуса — это первое, что нужно прочитать, поскольку следующее решение — какой поток читать — зависит от него.
  • В примере выполняется ветвление между getInputStream() и getErrorStream(). Здесь 201 означает успех, поэтому входной поток содержит отражённое тело, но при ответе 4xx/5xx getInputStream() выбросил бы исключение, а сообщение сервера было бы доступно только через getErrorStream(). Это разделение — самый острый край данного API.
  • Поток включал более пяти вызовов конфигурации для одного POST и disconnect() для завершения. Именно эта многословность — ручные потоки, ловушка с потоком ошибок, отсутствие встроенной асинхронности — является причиной появления HttpClient.

Когда использовать HttpURLConnection

Обращайтесь к HttpURLConnection, когда работаете со старым JDK (до Java 11), когда библиотека или кодовая база уже стандартизирована на нём, или когда вы хотите избежать подключения дополнительных зависимостей для одного простого вызова. Для всего нового и нетривиального — повторного использования соединений, HTTP/2, асинхронности или более удобных объектов запроса/ответа — предпочитайте современный HttpClient. Если вам нужно только читать данные по URL без HTTP-специфичного управления, достаточно обычных классов URL и URLConnection.

Практика

Практика
Клиент выполняет PUT через 'HttpURLConnection'. Когда сервер возвращает '400 Bad Request', код падает с 'IOException' в 'conn.getInputStream()' вместо того, чтобы записать сообщение об ошибке от сервера. Какое правильное исправление?
Клиент выполняет PUT через 'HttpURLConnection'. Когда сервер возвращает '400 Bad Request', код падает с 'IOException' в 'conn.getInputStream()' вместо того, чтобы записать сообщение об ошибке от сервера. Какое правильное исправление?
Was this page helpful?