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