Собственный протокол TCP может проходить через HTTP-прокси, когда этот прокси разрешает CONNECT к пункту назначения. Протокол приложения не обязан становиться HTTP: HTTP устанавливает туннель, а затем приложение обменивается своими байтами внутри него.

OpenJDK 25 предоставляет путь через HTTP-прокси в Socket(Proxy). Его реализация выполняет обмен CONNECT и возвращает подключённый сокет для использования приложением.

Proxy route = new Proxy(
    Proxy.Type.HTTP,
    new InetSocketAddress("proxy.example", 8080));

try (Socket socket = new Socket(route)) {
    socket.setSoTimeout(10000);
    socket.connect(
        InetSocketAddress.createUnresolved("tcp-service.example", 8443),
        5000);
    InputStream input = socket.getInputStream();
    OutputStream output = socket.getOutputStream();
}

Этот фрагмент использует классы из java.net и java.io. Замените обе конечные точки и выполните обмен протоколом до выхода из блока try. Для разрешённой публичной цели TCP выбирайте HTTP-кандидатов из списка HTTP-прокси только после проверки разрешения CONNECT для порта этой цели. Адрес прокси — это место, куда Java подключается первой; адрес, переданный в connect, определяет службу, до которой должен добраться прокси.

Неразрешённый пункт назначения сохраняет своё имя хоста для запроса CONNECT в этой реализации. Разрешённый InetSocketAddress, наоборот, передаёт этому запросу свой разрешённый IP-адрес. Это различие важно, когда прокси должен разрешить имя службы или применить политику на основе имени хоста.

Что оставляет успешное соединение

Полученные потоки несут данные службы, проходящей через туннель. Они не выдают отдельный HTTP-ответ, который ваше приложение должно было бы прочитать и отбросить. Добавление второго обмена CONNECT отправило бы службе текст HTTP после того, как JDK уже установил туннель.

Пример задаёт тайм-аут соединения и тайм-аут чтения из сокета; это отдельные средства управления, а не единый общий срок для сеанса приложения.

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

Если этому протоколу нужен TLS, согласуйте TLS через подключённый сокет с предполагаемым именем хоста службы и обычными проверками сертификата. Один CONNECT не шифрует поток. Для настоящего HTTP API HTTP-клиент остаётся более удобным интерфейсом, потому что он также обрабатывает сообщения HTTP.

Похожие статьи