openjdk.ruOpenJDK на русском

JEP 110: HTTP/2 Client (Incubator)

Клиент HTTP/2 (Incubator (инкубационный модуль))

ОтветственныйMichael McMahon
ТипFeature
ОбластьJDK
СтатусClosed / Delivered
Выпуск9
Компонентcore-libs / java.net
Обсуждениеnet dash dev at openjdk dot java dot net
ТрудоёмкостьXL
ДлительностьXL
Связан сJEP 244: TLS Application-Layer Protocol Negotiation Extension
JEP 321: HTTP Client API
РецензентыAlan Bateman
ОдобренBrian Goetz
Создан2014/05/12 16:26
Обновлён2026/07/29 19:02
Задача8042950

Аннотация

Определить новый API HTTP-клиента, который реализует HTTP/2 и WebSocket и может заменить устаревший API HttpURLConnection. API будет поставляться в JDK 9 как модуль Incubator, как определено в JEP 11. Это означает следующее:

  • API и реализация не будут частью Java SE.

  • API будет находиться в пространстве имён jdk.incubator.

  • По умолчанию модуль не будет разрешаться ни при компиляции, ни во время выполнения.

Мотивация

У существующего API HttpURLConnection и его реализации много проблем:

  • Базовый API URLConnection проектировался с расчётом на несколько протоколов, почти все из которых сейчас уже не используются (ftp, gopher и т. д.).

  • API появился раньше HTTP/1.1 и слишком абстрактен.

  • Им трудно пользоваться, у него много недокументированного поведения.

  • Он работает только в блокирующем режиме (то есть один поток на каждую пару запрос/ответ).

  • Его очень трудно сопровождать.

Цели

  • Должен быть прост в использовании в типичных случаях, в том числе должен иметь простой блокирующий режим.

  • Должен уведомлять о таких событиях, как «заголовки получены», ошибки и «тело ответа получено». Это уведомление не обязательно должно быть основано на обратных вызовах: можно использовать асинхронный механизм, например CompletableFuture.

  • Простой и лаконичный API, который покрывает 80–90 % потребностей приложений. Вероятно, это означает сравнительно небольшой API, который не обязательно открывает все возможности протокола.

  • Должен давать доступ ко всем значимым аспектам HTTP-запроса к серверу и ответа от сервера (заголовки, тело, коды состояния и т. д.).

  • Должен поддерживать стандартные и распространённые механизмы аутентификации. На первом этапе поддержка будет ограничена только аутентификацией Basic.

  • Должен позволять легко выполнить установку соединения (handshake) WebSocket.

  • Должен поддерживать HTTP/2. (Семантика HTTP/2 на уровне приложения в основном совпадает с 1.1, хотя протокол передачи данных совершенно другой.)

    • Должен уметь договариваться о переходе с 1.1 на 2 (или отказе от него) либо выбирать 2 с самого начала.

    • Должен поддерживать server push, то есть возможность сервера отправлять ресурсы клиенту без явного запроса со стороны клиента.

  • Должен выполнять проверки безопасности так же, как существующий сетевой API.

  • Желательно, чтобы он был удобен для использования с новыми возможностями языка, такими как лямбда-выражения.

  • Желательно, чтобы он учитывал требования встраиваемых систем, в частности не использовал постоянно работающие потоки таймеров.

  • Должен поддерживать HTTPS/TLS.

  • Требования к производительности для HTTP/1.1:

    • Производительность должна быть на уровне существующей реализации HttpURLConnection.

    • Производительность должна быть на уровне библиотеки Apache HttpClient, а также Netty и Jetty при их использовании в качестве клиентского API.

    • Потребление памяти новым API должно быть на том же уровне или ниже, чем у HttpURLConnection, Apache HttpClient, а также Netty и Jetty при их использовании в качестве клиентского API.

  • Требования к производительности для HTTP/2:

    • Производительность должна быть выше, чем у HTTP/1.1, в тех аспектах, которых ожидают от нового протокола (то есть по масштабируемости и задержке), с учётом любых ограничений платформы (например, окон подтверждения TCP-сегментов).

    • Производительность должна быть на уровне Netty и Jetty при их использовании в качестве клиентского API для HTTP/2.

    • Потребление памяти новым API должно быть на том же уровне или ниже, чем при использовании HttpURLConnection, Apache HttpClient, а также Netty и Jetty в качестве клиентского API.

  • Производительность будет сравниваться только для сопоставимых режимов работы, поскольку в новом API упор делается на простоту и удобство использования, а не на охват всех возможных сценариев,

  • Эта работа предназначена для JDK 9. Часть кода может быть повторно использована в Java EE в реализации HTTP/2 в Servlet 4.0 API, поэтому будут использоваться только возможности языка JDK 8 и, где это возможно, только API JDK 8.

  • Предполагается, что с учётом опыта использования API в JDK 9 его можно будет стандартизировать в Java SE в пространстве имён java.net в JDK 10. Когда это произойдёт, в рамках будущего JEP, API перестанет существовать в виде Incubator-модуля.

Что не является целью

Предполагается, что со временем этот API заменит API HttpURLConnection в новом коде, но мы не планируем сразу же переписывать старый API на основе нового. Это может быть сделано в дальнейшем.

Некоторые требования рассматривались в более ранних версиях этого JEP для JDK 8, но от них отказались, чтобы API был как можно проще:

  • фильтрация запросов и ответов,
  • подключаемый кэш соединений и
  • общий механизм перехода на другой протокол (upgrade).

Некоторые из этих требований, например кэширование соединений, станут менее важными по мере постепенного распространения HTTP/2.

Описание

Для JDK 9 была проведена работа над прототипом, в котором для HTTP-клиента, запросов и ответов были определены отдельные классы. Шаблон «строитель» (builder) использовался, чтобы отделить изменяемые сущности от неизменяемых результатов. Для отправки и получения определены синхронный блокирующий режим и асинхронный режим на основе java.util.concurrent.CompletableFuture.

Прототип был построен на NIO SocketChannels, а асинхронное поведение реализовано с помощью Selectors и предоставляемых извне ExecutorServices.

Реализация прототипа была автономной, то есть существующий стек не менялся, чтобы обеспечить совместимость и сделать возможным поэтапный подход, при котором с самого начала не требуется поддерживать всю функциональность.

API прототипа также включал:

  • раздельные запросы и ответы, как в Servlet API и API HTTP-сервера;
  • асинхронное уведомление о следующих событиях:
    • получены заголовки ответа,
    • ошибка ответа,
    • получено тело ответа и
    • server push (только HTTP/2);
  • HTTPS через SSLEngine;
  • работу через прокси;
  • cookie и
  • аутентификацию.

Больше всего доработки, вероятно, потребует та часть API, которая отвечает за поддержку множественных ответов HTTP/2 (server push) и настройку HTTP/2. Реализация прототипа поддерживает почти весь HTTP/1.1, но пока не поддерживает HTTP/2.

Работа через прокси для HTTP/2 будет реализована в одном из следующих изменений.

Альтернативы

Существует ряд API и реализаций HTTP-клиента, например Jetty и Apache HttpClient. Оба они довольно тяжеловесны с точки зрения количества пакетов и классов и не используют новые возможности языка, такие как лямбда-выражения.

Тестирование

Встроенный HTTP-сервер станет подходящей основой для регрессионных тестов и тестов TCK. Функциональные тесты тоже могут его использовать, но, возможно, их придётся проводить и на реальных HTTP-серверах.