News and views from members of the Java team at Oracle
Need to send or receive data from a remote service over HTTP? The HTTP Client added in JDK 11 improves upon and replaces the HttpUrlConnection API. In this article, we will explore how to use the new HttpClient and some new functionality it offers that wasn't available with HttpUrlConnection.
The HTTP Client was added in JDK 11 after first being introduced as an incubator feature in JDK 9. The goal of the HTTP Client was to replace HttpUrlConnection, which, along with having a difficult-to-use API, didn't offer support for protocols like HTTP/2 and WebSocket.
The HTTP Client addresses these shortcomings by offering support for the HTTP/2 and WebSocket, having an easier-to-use API, and adding new functionality like support for asynchronous calls and reactive streams.
A new instance of HttpClient is created through its builder API:
HttpClient client = HttpClient.newBuilder()
.version(Version.HTTP_1_1)
.followRedirects(Redirect.NORMAL)
.connectTimeout(Duration.ofSeconds(20))
.proxy(ProxySelector.of(...))
.authenticator(Authenticator.getDefault())
.build();
newBuilder() has methods for setting properties like; HTTP version, redirect behavior, proxies, timeout, an authenticator, and more. Once created, an HttpClient is immutable.
Like HttpClient, an HttpRequest is also created through its builder API:
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://openjdk.org/"))
.timeout(Duration.ofSeconds(10))
.header("Content-Type",
"application/json")
.GET()
.build()
The newBuilder() provides methods for setting properties like; URI, timeout, headers, HTTP method, and others. Like HttpClient, an HttpRequest is immutable; however, a request can be used multiple times.
##Sending Requests
Requests can be sent either as a synchronous blocking call or asynchronous non-block call.
HttpResponse<String> response =
client.send(request,
BodyHandlers.ofString());
System.out.println(response.statusCode());
System.out.println(response.body());
client.sendAsync(request,
BodyHandlers.ofString())
.thenApply(response ->
{ System.out.println
(response.statusCode());
return response;
} )
.thenApply(HttpResponse::body)
.thenAccept(System.out::println);
Asynchronous requests can also be used as a reactive stream. As a reactive stream, the HttpRequest acts as the publisher and the HttpResponse as the subscriber, with the corresponding methods in their classes for handling the stream:
public abstract class HttpRequest {
...
public interface BodyPublisher
extends Flow.Publisher<ByteBuffer>
{ ... }
}
public abstract class HttpResponse<T> {
...
public interface BodyHandler<T> {
BodySubscriber<T>
apply(int statusCode,
HttpHeaders responseHeaders);
}
public interface BodySubscriber<T>
extends
Flow.Subscriber<List<ByteBuffer>>
{ ... }
}
Happy coding!