Master Java 11 HttpClient: Sync & Async Requests with Full Code Guide
Learn how Java 11’s built‑in HttpClient simplifies both synchronous and asynchronous HTTP calls, covering client and request creation, setting URIs, methods, headers, timeouts, and various body types, with complete code examples and a comparison to alternative libraries.
1. Introduction
Before Java 11, Java only provided the HttpURLConnection API, which was hard to use and performed poorly. Consequently, most developers relied on third‑party libraries such as Apache HttpClient, Jetty, OkHttp, and Spring's RestTemplate.
Unlike HttpURLConnection, the Java 11 HTTP Client offers both synchronous and asynchronous request mechanisms.
The API includes three core classes: HttpRequest (represents the request to be sent), HttpClient (sends synchronous or asynchronous requests), and HttpResponse (represents the final result). The following sections describe them in detail.
2. HttpClient Synchronous and Asynchronous
Javadoc synchronous example:
<code>HttpClient client = HttpClient.newBuilder()
.version(Version.HTTP_1_1)
.followRedirects(Redirect.NORMAL)
.connectTimeout(Duration.ofSeconds(20))
.proxy(ProxySelector.of(new InetSocketAddress("proxy.example.com", 80)))
.authenticator(Authenticator.getDefault())
.build();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://www.dreamlu.net"))
.timeout(Duration.ofMinutes(2))
.header("Content-Type", "application/json")
.POST(BodyPublishers.ofFile(Paths.get("file.json")))
.build();
HttpResponse<String> response = client.send(request, BodyHandlers.ofString());
System.out.println(response.statusCode());
System.out.println(response.body());</code>In this case the program sends the request and waits for the response, then prints the status code and response body.
Now an asynchronous example:
<code>HttpClient client = HttpClient.newBuilder()
.build();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://www.dreamlu.net"))
.timeout(Duration.ofMinutes(2))
.header("Content-Type", "application/json")
.POST(BodyPublishers.ofFile(Paths.get("file.json")))
.build();
client.sendAsync(request, BodyHandlers.ofString())
.thenApply(HttpResponse::body)
.thenAccept(System.out::println);
</code>The example uses the sendAsync() method instead of send() ; send() performs a synchronous request, while sendAsync() issues an asynchronous request to any HTTP server or RESTful web service.
Next we look at adding timeout, headers, cookies, and other parameters.
3. HttpRequest Details
1. HttpRequest
HttpRequest represents the request to be sent. It can be created via
HttpRequest.newBuilder(). In JDK 16 a new
HttpRequest.newBuilder(HttpRequest request, BiPredicate filter)method copies configuration from an existing request.
2. Setting URI
Setting a URI is the first step when creating a new request. You can use the builder constructor with a URI parameter or call
uri(URI)on the builder.
<code>HttpRequest.newBuilder(new URI("https://www.dreamlu.net/get"))
HttpRequest.newBuilder()
.uri(new URI("https://www.dreamlu.net/get"))
</code>3. Setting HTTP Method
You can define the HTTP method using builder methods:
GET()
POST(BodyPublisher body)
PUT(BodyPublisher body)
DELETE()
Example of a simple GET request:
<code>HttpRequest request = HttpRequest.newBuilder()
.uri(new URI("https://www.dreamlu.net/get"))
.GET()
.build();
</code>4. Setting HTTP Version
The HttpClient API fully supports HTTP/2 and uses it by default. You can set the version with the builder’s
version()method.
<code>HttpRequest request = HttpRequest.newBuilder()
.uri(new URI("https://www.dreamlu.net/get"))
.version(HttpClient.Version.HTTP_2)
.GET()
.build();
</code>Note: If HTTP/2 is not supported, HttpClient automatically falls back to HTTP/1.1.
5. Setting Headers
Headers can be added easily via the builder’s
headers()method or multiple
header()calls.
<code>HttpRequest request = HttpRequest.newBuilder()
.uri(new URI("https://www.dreamlu.net/get"))
.headers("key1", "value1", "key2", "value2")
.GET()
.build();
HttpRequest request2 = HttpRequest.newBuilder()
.uri(new URI("https://www.dreamlu.net/get"))
.header("key1", "value1")
.header("key2", "value2")
.GET()
.build();
</code>6. Setting Timeout
Timeout defines how long to wait for a response; exceeding it throws
HttpTimeoutException. By default it is infinite, but you can set a
Durationvalue.
<code>HttpRequest request = HttpRequest.newBuilder()
.uri(new URI("https://www.dreamlu.net/get"))
.timeout(Duration.of(10, SECONDS))
.GET()
.build();
</code>7. Setting Request Body
You can add a body using
POST,
PUT, or
DELETEwith
BodyPublishers, or use
BodyPublishers.noBody()for an empty request.
<code>HttpRequest request = HttpRequest.newBuilder()
.uri(new URI("https://www.dreamlu.net/post"))
.POST(HttpRequest.BodyPublishers.noBody())
.build();
</code>8. Sending String Body
Use
BodyPublishers.ofString()(or the simple factory method
String()) to send a string as the request body.
<code>HttpRequest request = HttpRequest.newBuilder()
.uri(new URI("https://www.dreamlu.net/post"))
.headers("Content-Type", "text/plain;charset=UTF-8")
.POST(HttpRequest.BodyPublishers.ofString("Sample request body"))
.build();
</code>9. Sending InputStream Body
Pass an
InputStreamvia a
Supplier. Example uses a simple
ByteArrayInputStream.
<code>byte[] sampleData = "Sample request body".getBytes();
HttpRequest request = HttpRequest.newBuilder()
.uri(new URI("https://www.dreamlu.net/post"))
.headers("Content-Type", "text/plain;charset=UTF-8")
.POST(HttpRequest.BodyPublishers.ofInputStream(() -> new ByteArrayInputStream(sampleData)))
.build();
</code>10. Sending ByteArray
Use
BodyPublishers.ofByteArray()to send a byte array.
<code>byte[] sampleData = "Sample request body".getBytes();
HttpRequest request = HttpRequest.newBuilder()
.uri(new URI("https://www.dreamlu.net/post"))
.headers("Content-Type", "text/plain;charset=UTF-8")
.POST(HttpRequest.BodyPublishers.ofByteArray(sampleData))
.build();
</code>4. Conclusion
In terms of pure usability, the author finds Java 11 HttpClient less convenient than his open‑source
mica‑httplibrary (based on OkHttp). Example of a
mica‑httprequest:
<code>// synchronous, returns null on exception
String html = HttpRequest.get("https://www.baidu.com")
.connectTimeout(Duration.ofSeconds(1000))
.query("test", "a")
.query("name", "張三")
.query("x", 1)
.query("abd", Base64Util.encode("123&$#%"))
.queryEncoded("abc", Base64Util.encode("123&$#%"))
.execute()
.onFailed((request, e) -> {
e.printStackTrace();
})
.onSuccess(ResponseSpec::asString);
</code>As Spring Boot 3.x moves projects to Java 17, the built‑in HttpClient introduced in JDK 11 will become the optimal choice for SDK and middleware development.
Java Architecture Diary
Committed to sharing original, high‑quality technical articles; no fluff or promotional content.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.