
Java’s modern HttpClient (introduced in Java 11, fully stable through Java 21 and 25) is the canonical way to issue HTTP requests from server-side Java. For a simple synchronous GET, you do not need a third-party library, a framework, or a thread pool of your own.
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://reqres.in/api/users/2"))
.GET()
.build();
HttpResponse<String> response =
client.send(request, BodyHandlers.ofString());
System.out.println(response.statusCode());
System.out.println(response.body());
The client.send(...) call blocks the current thread until the response headers arrive (or the configured timeout trips). That is exactly what you want inside a virtual-thread-per-request server on modern JDKs: blocking is cheap again, and the code reads top-to-bottom.
When to go async instead
If you are in a classic platform-thread servlet stack, or you need to fan out dozens of outbound calls in parallel, swap send for sendAsync and chain a CompletableFuture. Set a Duration timeout on either the client or the request, and always use BodyHandlers that match the payload (ofString, ofByteArray, ofInputStream) to avoid loading huge responses into memory.
Charlie has over a decade of experience in website administration and technology management. As the site admin, he oversees all technical aspects of running a high-traffic online platform, ensuring optimal performance, security, and user experience.
























