Theory:Java 11 HTTP client
It is difficult to imagine modern applications working in complete isolation from the Internet. An application may need to load some pictures from external websites, store data, or send some statistics to different online services. Many of these interactions are done over the HTTP protocol which is a part of WWW. Java provides several well-defined and handy ways to interact with external resources over this protocol. In this topic, you will explore one up-to-date way of doing this.
# HTTP clients for Java
There are special types of libraries to interact over HTTP. They are called HTTP clients. They can look quite different but their purpose is always the same: to prepare and send HTTP requests to an external resource and to handle the response. These are some commonly used HTTP clients in Java:
- HttpURLConnection is the oldest of the clients and a part of the standard Java library. The client is pretty easy to use but it doesn't provide enough configuration options to be used in modern applications; its design is also a bit outdated, however, you can still use it for small applications.
- Apache HttpClient is an external open-source library and one of the most commonly used clients outside of the Java standard library. The client provides a rich set of features and configuration options, unlike HttpURLConnection, but it needs an additional external dependency for your project, as it is intended to be used in large applications and it can be overly complicated.
- Java 11 HTTP client is a new client for interacting over HTTP and, unlike Apache HttpClient, it is a part of Java Standard Library. The client became generally available in Java 11 and now it is a good alternative to all other HTTP clients: it is easy to start using the client and it provides plenty of configuration options. If you have Java 11+, we recommend that you use this client in your applications.
Now it's time to see how to use the new HTTP client in your applications.
# Java 11 HTTP client
The client is located in the java.net.http
package (the HttpClient
class) among some other related classes such as HttpRequest
and HttpResponse
. The purpose of most classes in this package is clear from their name, which makes programming easier and your code better.
To start using the client we need to follow these steps:
- Create an object of the
HttpClient
class to use it for further interactions; the same object can be used for multiple interactions. - Create a
URI
object that represents the address of the resource we would like to request. - Create an object of the
HttpRequest
class based on theURI
object and some configuration parameters. - Send the request by invoking the special methods of the
HttpClient
. - Get an object of
HttpResponse
as a result and process it.
Let's see how it works in practice. As an example, we are going to get the HTML representing the source of the first website (opens new window).
HttpClient httpClient = HttpClient.newHttpClient();
URI firstWebSiteAddress = URI.create("http://info.cern.ch/hypertext/WWW/TheProject.html");
HttpRequest request = HttpRequest.newBuilder()
.uri(firstWebSiteAddress)
.GET() // we can skip it, because the builder creates GET query by default
.build();
try {
HttpResponse<String> response = httpClient.send(
request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode()); // 200 if everything is OK
System.out.println(response.body()); // a long HTML text
} catch (Exception e) {
System.out.println("We cannot access the site. Please, try later.");
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
This code goes through exactly the same steps we've mentioned above, but with the following additions:
HttpResponse.BodyHandlers.ofString()
that is used to convert the result to a string (there are other types of converters but we aren't going to consider them now);- printing the status code and the response body as a string.
The code above receives the source HTML of the specified page and prints it together with the status code. Here is the shortened version of the output:
200
<HEADER>
<TITLE>The World Wide Web project</TITLE>
<NEXTID N="55">
</HEADER>
<BODY>
<H1>World Wide Web</H1>The WorldWideWeb (W3) is a wide-area<A
NAME=0 HREF="WhatIs.html">
hypermedia</A> information retrieval
initiative aiming to give universal
access to a large universe of documents.<P>
Everything there is online about
W3 is linked directly or indirectly
to this document, including an <A
NAME=24 HREF="Summary.html">executive
summary</A> of the project, <A
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
You are not restricted to sending only GET
requests when using this client. You can also specify POST
, PUT
and DELETE
as your request type. To demonstrate it, let's send a POST
request containing some data about a book as JSON to a special web service that accepts any data and returns some fake results.
HttpClient httpClient = HttpClient.newHttpClient();
URI fakePostService = URI.create("https://jsonplaceholder.typicode.com/posts");
String bookData = "{\"title\":\"The Invisible Man\", \"author\":\"H. G. Wells\"}";
HttpRequest request = HttpRequest.newBuilder()
.uri(fakePostService)
.header("Content-Type", "application/json") // we specify that we send a JSON
.POST(HttpRequest.BodyPublishers.ofString(bookData))
.build();
try {
var response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode()); // 201 if everything is OK
System.out.println(response.body()); // a JSON response with ID
} catch (Exception e) {
System.out.println("We cannot send data. Please, try later.");
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
In this example, we invoke HttpRequest.BodyPublishers.ofString(bookData)
to represent the data to be sent as a string. After receiving a response, we print its status code (201
if everything is OK) and the body containing an additional field called id
.
201
{
"title": "The Invisible Man",
"author": "H. G. Wells",
"id": 101
}
2
3
4
5
6
You can try sending different requests or access other websites to be sure that you fully get the idea of how to use the client.
It is recommended that you use the same client object to handle multiple requests rather than create a new client for each HTTP request. At the same time, it is not forbidden to have several clients across an application, although each of them should process multiple requests.
# Tips for interacting over HTTP
Interacting with a remote server over the Internet can be quite error-prone: the Internet connection can be lost, the server can be unavailable, the request can take too long to be processed, or the server can be just down. When developing applications, you need to handle various issues so that your application won't crash, users won't suffer from the errors or lose their data.
Here are some tips on what you can do:
- Handle exceptions to perform some fallback actions if we cannot reach the site because of connection issues. It is good practice to handle such exceptions because network errors are quite common and your application shouldn't crash due to them.
- Check
statusCode
before processing the body of a response because the result of the request could be different depending on the code:2XX
— success,4XX
— the request isn't correct,5XX
— an error on the server occurred. Most likely, if you get4XX
, you need to modify your code that sends HTTP requests; however, if you get5XX
, you need to wait and repeat your request later. - Set the timeout for any request, so that, if the server takes too long to process the request, the application will not wait for the response forever; it can be done when you're building your request using the dot syntax, e.g.:
.timeout(Duration.ofMillis(10000L))
.
You may wonder why we need both handling exceptions and checking status codes, but there is actually a big difference. An exception occurs when a request cannot be sent to the server or the response cannot reach your client, but the error status code indicates that although the interaction was OK, the server wasn't able to process the request.
If you need to repeat your request later, there are two options: you may ask users to repeat their actions later or you can just write an automatic loop mechanism for repetition. What to do depends on your app and its scenario. If you are writing an automatic mechanism, do not forget to specify the maximum number of repetitions, so as not to stay in the loop forever.
# Features and configuration options
As you can see, the client allows you to send any requests easily, but what it also does is provide a huge number of features and configuration options for adjusting your interaction to external services. Here is an incomplete list of them:
- you can send passwords and other authentication information via the client;
- the client supports different versions of protocols: HTTP/1.1, HTTP/2, WebSockets;
- it can be used to send asynchronous requests in order not to wait for the response and start processing it only when it is received;
- it is possible to access HTTP headers of the response;
- the client supports using cookies.
Having so many diverse features and configuration options makes it challenging to learn this library all at once, but the good news is that you don't have to memorize everything. If you need to find a feature or an option, just visit the official documentation (opens new window) and you will find out how to take advantage of this vast library in your particular case.
# Conclusion
Historically, Java has had several clients for working over the HTTP protocol. Some of them are part of the standard library while others are external tools. A new HTTP client Java 11 made generally available is a good alternative to all other clients. It combines the ease of use and a rich set of configuration options and features that are usually inherent in external libraries. Using the client, you can send any types of HTTP requests, process the responses, use several different protocols, and so much more. If you have Java 11+ and would like to write a new application, we strongly recommend that you try this new client!