How do I use Java 11 HttpClient to send asynchronous requests?

In Java 11, the HttpClient API provides a modern and user-friendly way to send both synchronous and asynchronous HTTP requests. To send asynchronous requests, you’ll use the sendAsync method, which returns a CompletableFuture.

Here’s how to use it:


Step-by-Step Guide to Sending Asynchronous Requests:

  1. Initialize the HttpClient:
    Use HttpClient to create an instance. This is the central object for sending requests.
  2. Create an HttpRequest:
    Prepare your HTTP request using the HttpRequest class, where you can specify the URI, HTTP method, headers, body, etc.
  3. Send an Asynchronous Request with sendAsync:
    Call the sendAsync method of the HttpClient, passing the request and body handler as arguments. This returns a CompletableFuture, which allows you to perform non-blocking operations.
  4. Process the Response:
    Use the CompletableFuture chain methods, like thenApply and thenAccept, to process the response once it’s available.

Example: Sending an Asynchronous GET Request

package org.kodejava.net.http;

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.concurrent.CompletableFuture;

public class AsyncHttpClientExample {

    public static void main(String[] args) {
        // Create HttpClient instance
        HttpClient client = HttpClient.newBuilder()
                .connectTimeout(Duration.ofSeconds(10)) // Optional timeout
                .build();

        // Prepare HttpRequest
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://jsonplaceholder.typicode.com/posts"))
                .GET()
                .header("Accept", "application/json")
                .build();

        // Send asynchronous request
        CompletableFuture<HttpResponse<String>> futureResponse =
                client.sendAsync(request, HttpResponse.BodyHandlers.ofString());

        // Process response asynchronously
        futureResponse.thenApply(HttpResponse::body) // Extract the response body
                .thenAccept(System.out::println) // Print the body
                .exceptionally(ex -> {
                    System.err.println("Request failed: " + ex.getMessage());
                    return null;
                });

        // Do other tasks while the response is being fetched...
        System.out.println("Request is sent. Waiting for response...");

        // Wait until the response completes to prevent the program from exiting early
        futureResponse.join();
    }
}

Explanation:

  1. HttpClient.newBuilder():
    Creates a new instance of the HttpClient. You can optionally configure timeouts, proxies, or redirect policies.
  2. HttpRequest.newBuilder():
    Creates an HTTP request. You specify the URI, headers, and HTTP method (e.g., GET, POST, etc.).
  3. sendAsync:
    Sends the request asynchronously. It accepts two arguments:

    • The HttpRequest object.
    • A BodyHandler to determine how the HTTP response body should be handled, such as ofString() for plain text.
  4. CompletableFuture Chain:
    • thenApply: Manipulates the asynchronous result as it becomes available.
    • thenAccept: Consumes the result of the future once it’s ready.
    • exceptionally: Handles any exceptions that occur during execution.
  5. join():
    Blocks the main thread until the asynchronous operation is complete (used here to prevent premature termination of the program).

Example: Sending an Asynchronous POST Request with JSON Body

package org.kodejava.net.http;

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.concurrent.CompletableFuture;

public class AsyncPostExample {

    public static void main(String[] args) {
        // Create HttpClient
        HttpClient client = HttpClient.newBuilder()
                .connectTimeout(Duration.ofSeconds(10))
                .build();

        // Prepare JSON body
        String jsonBody = "{ \"title\": \"foo\", \"body\": \"bar\", \"userId\": 1 }";

        // Create HttpRequest
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://jsonplaceholder.typicode.com/posts"))
                .POST(HttpRequest.BodyPublishers.ofString(jsonBody))
                .header("Content-Type", "application/json")
                .build();

        // Send asynchronous POST request
        CompletableFuture<HttpResponse<String>> futureResponse =
                client.sendAsync(request, HttpResponse.BodyHandlers.ofString());

        // Handle response
        futureResponse.thenApply(HttpResponse::body)
                .thenAccept(System.out::println)
                .exceptionally(ex -> {
                    System.err.println("Error: " + ex.getMessage());
                    return null;
                });

        // Keep the program running to wait for response
        System.out.println("POST request sent. Waiting for response...");
        futureResponse.join();
    }
}

Keynotes:

  • Thread-Safe HttpClient:
    The HttpClient instance is thread-safe and can be reused for multiple requests.
  • Non-blocking Nature:
    Asynchronous requests are non-blocking, so you can perform other tasks while waiting for the response.
  • Error Handling:
    Use the exceptionally method of the CompletableFuture to handle any errors during the request.
  • Keepalive:
    By default, HttpClient connections have keepalive enabled. It’s more efficient for high-performance applications.
  • Timeouts:
    Always configure timeouts to prevent indefinite blockage (connectTimeout or read timeouts).

Using this approach, you can efficiently perform asynchronous HTTP communication with HttpClient.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.