사용자 지정 TCP 프로토콜은 프록시가 목적지로의 CONNECT를 허용할 때 HTTP 프록시를 통과할 수 있습니다. 애플리케이션 프로토콜이 HTTP가 될 필요는 없습니다. HTTP가 터널을 만들고, 그 안에서 애플리케이션이 자체 바이트를 주고받습니다.

OpenJDK 25는 Socket(Proxy)에 HTTP 프록시 경로를 제공합니다. 그 구현은 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 대상의 경우 해당 대상 포트에 대한 CONNECT 권한을 확인한 뒤에만 HTTP 프록시 목록에서 HTTP 후보를 고르십시오. 프록시 주소는 Java가 먼저 연결하는 곳이고, connect에 전달되는 주소는 프록시가 도달해야 할 서비스를 식별합니다.

해석되지 않은 목적지는 이 구현의 CONNECT 요청을 위해 호스트 이름을 유지합니다. 반면 해석된 InetSocketAddress는 해당 요청에 해석된 IP 주소를 제공합니다. 이 차이는 프록시가 서비스 이름을 해석해야 하거나 호스트 이름 기반 정책을 적용해야 할 때 중요합니다.

성공한 연결이 남기는 것

생성된 스트림은 터널링된 서비스의 데이터를 나릅니다. 애플리케이션이 읽고 버려야 할 별도의 HTTP 응답은 노출되지 않습니다. 두 번째 CONNECT 교환을 추가하면 JDK가 이미 터널을 설정한 뒤에 HTTP 텍스트를 서비스로 보내게 됩니다.

예제는 연결 시간 제한과 소켓 읽기 시간 제한을 설정합니다. 이는 별개의 제어이며, 애플리케이션 세션 전체에 대한 하나의 기한이 아닙니다.

CONNECT 권한은 여전히 프록시에 있습니다. 일반 웹 요청을 전달하는 끝점은 서비스 포트를 거부하거나 터널을 열기 전에 인증을 요구할 수 있습니다. 그러한 실패는 터널을 수락한 뒤 애플리케이션 프로토콜을 거부하는 서버와 구분해 두십시오.

그 프로토콜에 TLS가 필요하면 연결된 소켓을 통해 서비스의 의도된 호스트 이름과 일반적인 인증서 검사로 TLS를 협상하십시오. CONNECT만으로는 스트림이 암호화되지 않습니다. 실제 HTTP API의 경우 HTTP 클라이언트가 HTTP 메시지도 처리하므로 더 편리한 인터페이스로 남습니다.

관련 글