Java URLConnection
Открывайте соединения с URL в Java через URLConnection для чтения ресурсов и отправки запросов.
URL называет ресурс; URLConnection — это живая ссылка, которую вы открываете, чтобы фактически читать или записывать его. Вы никогда не создаёте её напрямую — вы вызываете url.openConnection(), и Java возвращает объект соединения, конкретный тип которого зависит от протокола (http:, https:, file:, jar:, …). URLConnection — это протокол-нейтральный базовый класс; в главе HttpURLConnection рассматривается его HTTP-специфичный подкласс.
На этой странице описывается, как открыть соединение, настроить тайм-ауты, прочитать заголовки ответа и тело, а также где заканчивается протокол-нейтральный API и начинается HTTP-специфичная работа.
Открытие и настройка
URL url = URI.create("http://example.com/data").toURL();
URLConnection conn = url.openConnection(); // not connected yet
conn.setConnectTimeout(2000); // ms to establish the connection
conn.setReadTimeout(2000); // ms to wait for data
conn.connect(); // optional; reading connects implicitlyopenConnection() не обращается к сети — он просто создаёт настраиваемый объект. Фактическое соединение устанавливается лениво при вызове connect() или, что более типично, при первом чтении из getInputStream(). Устанавливайте тайм-ауты до подключения; оба по умолчанию равны 0, что означает «ждать вечно» — это редко то, что вам нужно.
Чтение ответа
Возвращается два вида информации: заголовки (метаданные) и тело (поток ввода).
String type = conn.getContentType(); // e.g. "text/plain; charset=utf-8"
int length = conn.getContentLength(); // -1 if the server did not send it
long when = conn.getLastModified();
try (InputStream in = conn.getInputStream()) {
// read the body bytes
}Методы-получатели заголовков, такие как getContentType(), — это удобные обёртки над общим методом getHeaderField("Name"). Всегда читайте тело через try-with-resources, чтобы базовый сокет был освобождён.
Отправка данных
Чтобы отправить тело запроса, переключите соединение в режим вывода с помощью setDoOutput(true), затем записывайте в getOutputStream(). Для HTTP это подразумевает POST. Поскольку управление методом, кодом состояния и потоком ошибок требует HTTP-специфичного поведения, эта работа принадлежит HttpURLConnection.
Практический пример: чтение ресурса через соединение
Эта программа предоставляет небольшое текстовое тело через loopback HttpServer, открывает к нему обобщённый URLConnection, проверяет заголовки ответа и построчно читает тело — полностью в автономном режиме.
Что следует вынести из этого запуска:
url.openConnection()вернулURLConnectionбез подключения; сетевой обмен произошёл только при вызовеgetInputStream(). Именно эта ленивость является причиной, по которой тайм-ауты и свойства запроса должны быть установлены заранее — как только вы начнёте читать тело, соединение уже установлено и эти настройки зафиксированы.- Методы-получатели заголовков и поток тела — это два отдельных канала.
getContentType()иgetContentLength()читают метаданные ответа, аgetInputStream()читает полезную нагрузку. Сервер явно задалContent-Type, и соединение предоставило его как через типизированный получатель, так и через обобщённыйgetHeaderField("Content-Type"). getContentLength()вернул реальное число байт, потому что сервер отправил заголовокContent-Length. Когда сервер его опускает (chunked-ответы), возвращается-1— поэтому код, предварительно выделяющий буфер на основе этого значения, должен обрабатывать случай-1.- Тело было прочитано через try-with-resources, что гарантирует освобождение сокета даже при исключении. Утечка потоков соединений исчерпывает пул соединений и в конечном счёте лимит файловых дескрипторов ОС — закрытие обязательно в сетевом коде.
URLConnectionнамеренно является протокол-нейтральным: здесь нет ничего о HTTP-кодах состояния или методах запроса. Чтение статуса, выбор между GET и POST и доступ к потоку ошибок требуют приведения кHttpURLConnection, что и делается в следующей главе.