HTTP/2는 HTTP/1.1의 복잡한 인프라를 유지하면서 발생하는 고통을 완화하는 것을 목표로 하며 좋은 성능을 가지고 있습니다. HTTP/2는 여전히 HTTP/1.1과 역호환되지만 더 이상 텍스트 기반 프로토콜이 아닙니다.
HTTP/2 멀티플렉싱을 사용하면 단일 연결로 여러 양방향 스트림을 처리할 수 있으므로 클라이언트는 단일 연결을 통해 여러 리소스를 동시에 다운로드할 수 있습니다.
HTTP 1.x 프로토콜은 텍스트 기반이므로 메시지가 매우 깁니다. 때로는 동일한 HTTP 헤더 세트가 계속해서 교환됩니다. HTTP/2는 요청 전반에 걸쳐 HTTP 헤더를 유지 관리하여 반복적인 데이터 교환을 제거하고 데이터 상호 작용에 필요한 대역폭을 크게 줄입니다.
HTTP/2의 서버 측 데이터 푸시가 WebSocket의 일종의 지속 또는 업그레이드라고 생각할 수도 있지만 그렇지 않습니다. WebSocket은 TCP 연결이 설정된 후 서버가 클라이언트에 데이터를 전송하도록 클라이언트와 서버 간의 전이중 통신 방법인 반면, HTTP/2는 다른 솔루션을 제공합니다.
HTTP/2 푸시는 클라이언트 관점에서 리소스 요청을 시작하지 않고 클라이언트에 리소스를 적극적으로 보내는 것입니다. 즉, 서버는 요청을 통해 웹 사이트에 추가로 필요한 다른 리소스가 무엇인지 알 수 있으며 클라이언트가 다시 요청하기 훨씬 전에 (미리) 리소스를 모두 함께 보낼 수 있습니다.
Jetty
Netty
OkHttp
Vert.x
Firefly
하지만 이번 글에서는 소개하지 않겠습니다. 이러한 Java 클라이언트 소프트웨어는 Java9에서 제공하는 HTTP/2 지원을 도입합니다.
먼저 Java 9 구문을 사용하여 모듈을 가져옵니다. jdk.incubator.httpclient
module com.springui.echo.client { requires jdk.incubator.httpclient; }
Java 9의 새로운 HTTP 클라이언트 API는 빌더 패턴을 따릅니다. HttpClient는 HTTP 요청을 처리하는 데 사용되는 진입점입니다. 먼저 빌드된 후 사용됩니다.
HttpClient client = HttpClient .newBuilder() .version(Version.HTTP_2) //支持HTTP2 .build();
HttpClient 인스턴스가 있으면 이를 사용하여 HttpRequest를 보낼 수 있습니다. 생성자를 사용하여 HttpRequest 인스턴스를 만들 수도 있습니다.
HttpResponse<String> response = client.send( HttpRequest .newBuilder(TEST_URI) //请求地址 .POST(BodyProcessor.fromString("Hello world")) //POST报文数据 .build(), BodyHandler.asString() //请求响应数据处理,接收字符串 );
요청이 전송된 후 응답 데이터를 얻을 때까지 스레드가 차단됩니다. 이는 JAVA 8 이하의 HTTP API와 동일합니다. 그러나 Java 9는 비동기식 비차단 요청 전송 및 처리 방법을 제공하며 이는 동시 HTTP 요청 및 처리에 더 적합합니다.
아래 예에서는 10개의 임의의 정수가 비동기식으로 전송됩니다.
List<CompletableFuture<String>> responseFutures = IntStream.of(1,2,3,4,5,6,7,8,9,10) //10个整数形成IntStream,Java 8的语法 .mapToObj(String::valueOf) //10个整数转换成字符串,Java 8的语法 .map(message -> client.sendAsync( //将10个整数字符串作为内容,发送10个异步请求 HttpRequest.newBuilder(TEST_URI) .POST(HttpRequest.BodyProcessor.fromString(message)) .build(), HttpResponse.BodyHandler.asString() ).thenApply(HttpResponse::body) //以CompletableFuture<HttpResponse.body()>作为流处理的返回值 ) .collect(Collectors.toList()); //将Stream转成List
위의 예에서는 Java 8의 스트림 스트리밍 API를 광범위하게 사용합니다. 익숙하지 않은 경우 이전에 작성한 기사를 읽어보세요.
sendAsync 메서드의 반환 값은 CompletableFuture721c5bd4f0360fdcda122bb99928a389>이며, 이는 thenApply(HttpResponse::body)를 사용하여 추가 처리되며, 최종 반환 값은 CompletableFuturef7e83be87db5cd2d9a8a0b8117b38cd4입니다.
CompletableFuture는 동시 비동기 처리 결과를 인쇄하는 Java 비동기 프로그래밍에 대한 지식입니다.
responseFutures.stream().forEach(future -> { LOGGER.info("Async response: " + future.getNow(null)); });
모든 요청이 비동기적으로 전송되기 때문에 최종 인쇄 로그가 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 순서대로 처리되지 않을 수 있음을 알 수 있습니다. 반환되는 결과는 CompletableFuture는 비동기 처리에 사용됩니다.
위의 모든 예제는 HTTP/1.1 프로토콜에서 완료될 수 있지만 새로운 비차단 비동기 API가 추가되었으며 HTTP/2 기능은 포함되지 않습니다. 걱정하지 마세요. Java 9 클라이언트 API는 HTTP/2와 가장 밀접하게 통합되어 있습니다. HTTP2를 사용하여 요청을 보내고 여러 비동기 데이터 결과를 얻을 수 있습니다. (일부 데이터는 미리 푸시됩니다. 물론 이를 위해서는 서버가 협력을 위해 HTTP/2도 지원해야 합니다.)
Map<HttpRequest,CompletableFuture<HttpResponse<String>>> responses = client.sendAsync( //注意这里只发送一次请求 HttpRequest.newBuilder(TEST_URI) .POST(HttpRequest.BodyProcessor.fromString(TEST_MESSAGE)) .build(), HttpResponse.MultiProcessor.asMap( //多个资源的响应结果 request -> Optional.of(HttpResponse.BodyHandler.asString()) ) ).join(); responses.forEach((request, responseFuture) -> { LOGGER.info("Async response: " + responseFuture.getNow(null)); });
Java 9의 관점에서 볼 때 새로운 HTTP/2 클라이언트 API는 좋아 보입니다. 하지만 저자는 현재 관련 기술의 활용이 아직 그다지 성숙되지 않았다고 생각합니다.
위 내용은 Java 9의 HTTP2 프로토콜 지원 및 비차단 HTTP API 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!