1. Introduction
In this short tutorial, we’ll look at how to send HTTP requests containing compressed data.
In addition, we’ll look at how to configure a Spring web application so it handles compressed requests.
2. Sending Compressed Requests
Firstly, let’s create a method that compresses a byte array. This will come in handy shortly:
public static byte[] compress(byte[] body) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (GZIPOutputStream gzipOutputStream = new GZIPOutputStream(baos)) {
gzipOutputStream.write(body);
}
return baos.toByteArray();
}
Next, we need to implement a ClientHttpRequestInterceptor to modify the request. Note that we’ll both send the appropriate HTTP compression headers as well as call our body-compressing method:
public ClientHttpResponse intercept(HttpRequest req, byte[] body, ClientHttpRequestExecution exec)
throws IOException {
HttpHeaders httpHeaders = req.getHeaders();
httpHeaders.add(HttpHeaders.CONTENT_ENCODING, "gzip");
httpHeaders.add(HttpHeaders.ACCEPT_ENCODING, "gzip");
return exec.execute(req, compress(body));
}
Our interceptor takes the outbound request body and compresses it using the GZIP format. In this example, we use Java’s standard GZIPOutputStream to do the work for us.
In addition, we must add the appropriate headers for data encoding. This lets the destination endpoint know it is dealing with GZIP-compressed data.
Finally, we add the interceptor to our RestTemplate definition:
@Bean
public RestTemplate getRestTemplate() {
RestTemplate restTemplate = new RestTemplate();
restTemplate.getInterceptors().add(new CompressingClientHttpRequestInterceptor());
return restTemplate;
}
3. Handling Compressed Requests
By default, most web servers do not understand requests containing compressed data. Spring web applications are no different. Therefore, we need to configure them to handle such requests.
Currently, only the Jetty and Undertow web servers handle request bodies with data in GZIP format. Please see our article on Spring Boot Application Configuration to set up a Jetty or Undertow web server.
3.1. Jetty Web Server
In this example, we customize a Jetty web server by adding a Jetty GzipHandler. This Jetty handler is built to compress responses and decompress requests.
However, adding it the Jetty web server is not enough. We need to set the inflateBufferSize to a value greater than zero to enable decompression:
@Bean
public JettyServletWebServerFactory jettyServletWebServerFactory() {
JettyServletWebServerFactory factory = new JettyServletWebServerFactory();
factory.addServerCustomizers(server -> {
GzipHandler gzipHandler = new GzipHandler();
gzipHandler.setInflateBufferSize(1);
gzipHandler.setHandler(server.getHandler());
HandlerCollection handlerCollection = new HandlerCollection(gzipHandler);
server.setHandler(handlerCollection);
});
return factory;
}
3.2. Undertow Web Server
Likewise, we can customize an Undertow web server to automatically decompress requests for us. In this case, we need to add a custom RequestEncodingHandler.
We configure the encoding handler to process GZIP source data from the request:
@Bean
public UndertowServletWebServerFactory undertowServletWebServerFactory() {
UndertowServletWebServerFactory factory = new UndertowServletWebServerFactory();
factory.addDeploymentInfoCustomizers((deploymentInfo) -> {
deploymentInfo.addInitialHandlerChainWrapper(handler -> new RequestEncodingHandler(handler)
.addEncoding("gzip", GzipStreamSourceConduit.WRAPPER));
});
return factory;
}
4. Conclusion
And that’s all we need to do to get compressed requests working!
In this tutorial, we covered how to create an interceptor for a RestTemplate that compresses the content of a request. Also, we looked at how to automatically decompress these requests in our Spring web applications.
It’s important to note that we should only send compressed content to web servers capable of handling such requests.
A complete working example for the Jetty web server is over on GitHub.