W3docs

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 implicitly

openConnection() не обращается к сети — он просто создаёт настраиваемый объект. Фактическое соединение устанавливается лениво при вызове 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, проверяет заголовки ответа и построчно читает тело — полностью в автономном режиме.

java— editable, runs on the server

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

  • 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, что и делается в следующей главе.

Практика

Практика
Подпрограмма загрузки вызывает 'url.openConnection()', а затем сразу запускает 30-секундный таймер перед вызовом 'getInputStream()', ожидая, что соединение уже открыто. Тайм-ауты при этом не устанавливаются. Какое утверждение верно?
Подпрограмма загрузки вызывает 'url.openConnection()', а затем сразу запускает 30-секундный таймер перед вызовом 'getInputStream()', ожидая, что соединение уже открыто. Тайм-ауты при этом не устанавливаются. Какое утверждение верно?
Was this page helpful?