Servlet 4.0
For the majority of developers, this may not impact the way you write servlet code, but it does offer some performance benefits along with new abilities such as server push. HTTP/2.0 is a binary protocol based on frames and is the new standard for the web. HTTP/2 standard was approved around February 2015 and is supported by most modern day browsers. While the web has been evolving at a fast pace, the same can't be said about HTTP itself. For years, developers had to work around the limitations of HTTP 1.x, but the wait is finally over, as this version has better alignment with modern day demands. Some of the HTTP/2 benefits include the ability to reuse the same TCP connection for multiple requests, more compressed header information, priority and packet streaming, and server push to send resources from the server to the client. This results in reduced latency with faster content downloads. For the uninformed, this change won't be a crucial change and your applications will continue to function as they did before with the added benefit of faster performance.
So, there are no new HTTP methods and no new headers or URL changes that you need to worry about. Since Java EE servlets are primarily based on the HTTP protocol, it was only logical for it to get updated to meet the changes in the HTTP standards. The 4.0 update is mainly focused on adding support for the HTTP/2.0 standard, and thus is a 100% compliant implementation for the HTTP/2 specification. What this update should bring with it is increased performance.
Some of the features of HTTP/2 are:
- Request/response multiplexing (bi-directional support)
- Optimized headers (uses HPACK header compression)
- Binary frames (this solves the HOL blocking problem present in HTTP/1.1)
- Server Push
- Stream prioritization
- Upgrade from HTTP/1.0
Servlet 4.0 serves as an abstraction of the underlying protocol, allowing us to focus on the high-level APIs that shield us from the intricacies of HTTP. It's also interesting to note that the servlet specification itself is relied upon by other specs, such as JSF, which will be utilizing these updates to their benefit. Typically, you can think of an HTTP request/response cycle as one request and one response, but that just changed. Now one request can be used to send out multiple responses. To put this into perspective, remember the earlier workarounds of HTTP 1.1, such as domain sharding or where we tried to save multiple requests in order to reduce the TCP connection overhead, such as using CSS Sprites (one image combined with multiple images), well that’s no longer needed.
Server Push
There's a new Push builder API that can be used for server push features. Armed with the server push ability, a server can push a resource to the client. This doesn't mean that there's no request needed in the first place. You need to obtain a PushBuilder
from the request object and then use this for constructing a push request. Thus, there's always a request, based on which, the push feature is enabled.
A sample of this is as follows:
PushBuilder pushBuilder = httpServletRequest.newPushBuilder();
Once a pushBuilder
instance is obtained from the request, you can use it to set the required URI path, which is to be used for sending the push request. A sample is shown here:
request.newPushBuilder() .path(“/assests/images/product.png”) .push();
Here, the paths beginning with /
are considered absolute paths. Without the /
prefix, the path would be considered to be relative to the context of the request used to create the instance of PushBuilder
. While the short code shown here is handy, it must be used with caution since there's a possibility that the call to newPushBuilder()
may return null
if push is not supported.
If you are wondering how we put that newPushBuilder
method on the request object, remember that Java 8 has default methods. So, the signature of the method looks like the following:
default PushBuilder newPushBuilder()
Building a push request involves setting the request method to GET
and setting the path
explicitly, as that won't be set by default. Calling the push
method generates the push request from the server and sends it to the client, unless the push feature is not available for some reason. You may add headers or query strings to the push request by using the addHeader
or queryString
methods.
With the preceding code, the server will send a push to the client that made this request. The client may already have the resource and thus can tell the server that it has this cached from a previous request, and in turn will inform the server to not bother sending this resource over the wire. You might have guessed by now that it's the client who can dictate whether a resource should be pushed or not. Thus, the client can explicitly disable the server push.
Let's imagine we need to push the logo to the client from our servlet. Here's how we might write this code:
protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { PushBuilder pushBuilder = request.newPushBuilder(); if (pushBuilder != null) { pushBuilder.path("images/logo.png") .addHeader("Content-Type", "image/png") .push(); } try (PrintWriter writer = response.getWriter();) { writer.write(new StringBuilder() .append("<html><body>") .append("<img src='images/logo.png'>") .append("</body></html>").toString()); } }
The Servlet API already provides Java SE 9 support for HTTP/2. There’s broadly just two classes, HttpRequestGroup
and HttpRequest
. These are just enough to solve the most common use cases but not exhaustive enough to replace a more established HTTP client library. It will support both the earlier HTTP/1 version along with the newer HTTP/2 version.