Migration to Apache HttpClient 5.0 async APIs for HTTP/2 only

For those scenarios where HTTP/1.1 compatibility is no longer required HttpClient 5.0 provides CloseableHttpAsyncClient optimized for HTTP/2 protocol with full support for multiplexed request execution over a single HTTP/2 connection.

Migration steps

  • Replace the default client builder with HTTP/2 specific one. Request and response handlers do not require any modification.

Please note HTTP/2 clients do not have a connection manager. They maintain an internal map of active connections, one per distinct origin host. Therefore, TLS settings can be applied directly to the client instance, not a connection manager.

Please note that presently HTTP/2 clients do not support request execution via an HTTP proxy.

CloseableHttpAsyncClient client = HttpAsyncClients.customHttp2()
      .setTlsStrategy(ClientTlsStrategyBuilder.create()
              .setSslContext(SSLContexts.createSystemDefault())
              .setTlsVersions(TLS.V_1_3, TLS.V_1_2)
              .build())
      .setIOReactorConfig(IOReactorConfig.custom()
              .setSoTimeout(Timeout.ofSeconds(5))
              .build())
      .setDefaultRequestConfig(RequestConfig.custom()
              .setConnectTimeout(Timeout.ofSeconds(5))
              .setResponseTimeout(Timeout.ofSeconds(5))
              .setCookieSpec(StandardCookieSpec.STRICT)
              .build())
      .build();
client.start();

CookieStore cookieStore = new BasicCookieStore();

CredentialsProvider credentialsProvider = new BasicCredentialsProvider();

HttpClientContext clientContext = HttpClientContext.create();
clientContext.setCookieStore(cookieStore);
clientContext.setCredentialsProvider(credentialsProvider);
clientContext.setRequestConfig(RequestConfig.custom()
      .setConnectTimeout(Timeout.ofSeconds(10))
      .setResponseTimeout(Timeout.ofSeconds(10))
      .build());

JsonFactory jsonFactory = new JsonFactory();
ObjectMapper objectMapper = new ObjectMapper(jsonFactory);

HttpRequest httpPost = BasicHttpRequests.post("https://nghttp2.org/httpbin/post");

List<NameValuePair> requestData = Arrays.asList(
      new org.apache.http.message.BasicNameValuePair("name1", "value1"),
      new org.apache.http.message.BasicNameValuePair("name2", "value2"));

Future<?> future = client.execute(
      JsonRequestProducers.create(httpPost, requestData, objectMapper),
      JsonResponseConsumers.create(jsonFactory),
      new FutureCallback<Message<HttpResponse, JsonNode>>() {

          @Override
          public void completed(Message<HttpResponse, JsonNode> message) {
              System.out.println(message.getBody());
          }

          @Override
          public void failed(Exception ex) {
              System.out.println("Error executing HTTP request: " + ex.getMessage());
          }

          @Override
          public void cancelled() {
              System.out.println("HTTP request execution cancelled");
          }

      });

future.get();
client.close(CloseMode.GRACEFUL);