Spring Top

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE
REST Top

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE

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.

Spring bottom

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE
REST bottom

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE

Leave a Reply

avatar
  Subscribe  
Notify of