Spring Boot Gzip Compression: Global vs. URLs Specific

Learn to enable HTTP response gzip compression in a Spring Boot application. By default, the gzip compression is disabled in Spring Boot.

Spring boot http compression

Gzip compression is a technique used to reduce the size of HTTP responses by compressing them before sending them over the network. Learn to enable HTTP response gzip compression in a Spring Boot application.

By default, the Gzip compression is disabled in Spring Boot.

1. Enable Gzip Compression “Globally”

1.1. Properties Configuration

The following response compression-related Spring Boot properties are applicable to Jetty, Tomcat, and Undertow. Define these properties in the application.properties file.

server.compression.enabled=true
server.compression.mime-types=application/json,application/xml,text/html,text/xml,text/plain
server.compression.min-response-size=1024
server.compression.excluded-user-agents=MSIE 6.0,UCBrowser

A similar configuration can be written in YAML as follows:

server:
  compression:
    enabled: true
    mime-types: application/json,application/xml,text/html,text/xml,text/plain
    min-response-size: 1024
    excluded-user-agents: MSIE 6.0,UCBrowser
  • server.compression.enabled enables or disables the compression.
  • server.compression.min-response-size – configures the minimum number of bytes in response for compression to be performed. The default size is 2048 bytes.
  • server.compression.mime-types – enables compression only if their content type is one of the given mime-types.
  • server.compression.excluded-user-agents – specifies a comma-separated list of user-agent patterns for which Gzip compression should be excluded.

1.2. Wildcards in Mime-types are not Supported

The compression in Spring Boot relies on support provided by underlying embedded servers. Unfortunately, these servers do not provide any consistent wildcard support in mime-type.

1.2.1. Jetty

Jetty performs strict string comparisons when determining whether to compress a response based on MIME type. Wildcards such as * are not supported directly for matching multiple MIME types. [Link]

However, Jetty provides an alternative mechanism for configuring a whitelist or blacklist of MIME types explicitly. This allows you to specify which MIME types should or should not be compressed.

For example, you might configure a whitelist to explicitly list the MIME types that should be compressed:

server.compression.mime-types=application/json,application/xml,text/html

1.2.2. Tomcat

While Tatomc doesn’t support wildcards in the traditional sense, you can configure MIME types in a way that covers a range of similar types. [Link]

So configuring ‘application/vnd.company‘ would work for both ‘application/vnd.company.v3+json‘ and ‘application/vnd.company.v2+xml‘.

server.compression.mime-types=application/json,application/xml,application/vnd.company

2. Enable Gzip Compression for Specific URLs Only

The default compression (using properties) is applied to all responses sent from the server. If we need more control over when to apply the compression and when to skip it, we can create a custom filter.

In the following example, we create the GzipResponseCompressionFilter class, a Servlet 3.0 filter. In it’s doFilter() method, we check the URL pattern and any additional pre-checks (such as the client has requested for compressed output?), and return the gzip compressed output, if needed.

@WebFilter(urlPatterns = {"/pattern-1", "/pattern-2" , "/*"})
public class GzipResponseCompressionFilter implements Filter {

  @Override
  public void init(FilterConfig filterConfig) throws ServletException {
  }

  @Override
  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
      throws IOException, ServletException {

    HttpServletRequest httpRequest = (HttpServletRequest) request;
    HttpServletResponse httpResponse = (HttpServletResponse) response;

    if (acceptsGZipEncoding(httpRequest)) {
      CustomHttpServletResponseWrapper gzipResponse = new CustomHttpServletResponseWrapper(httpResponse);
      gzipResponse.setHeader("Content-Encoding", "gzip");
      chain.doFilter(request, gzipResponse);
      gzipResponse.close();
    } else {
      chain.doFilter(request, response);
    }
  }

  @Override
  public void destroy() {
  }

  private boolean acceptsGZipEncoding(HttpServletRequest request) {
    String acceptEncoding = request.getHeader("Accept-Encoding");
    return acceptEncoding != null && acceptEncoding.contains("gzip");
  }
}

The CustomHttpServletResponseWrapper and CustomServletOutputStream classes handle the actual compression and wrap the uncompressed response into a compressed one.

class CustomHttpServletResponseWrapper extends HttpServletResponseWrapper {

  private GZIPOutputStream gzipOutputStream;
  private ServletOutputStream outputStream;
  private PrintWriter writer;

  public CustomHttpServletResponseWrapper(HttpServletResponse response) throws IOException {
    super(response);
    this.gzipOutputStream = new GZIPOutputStream(response.getOutputStream());
  }

  @Override
  public ServletOutputStream getOutputStream() throws IOException {
    if (this.outputStream == null) {
      this.outputStream = new CustomServletOutputStream(this.gzipOutputStream);
    }
    return this.outputStream;
  }

  @Override
  public PrintWriter getWriter() throws IOException {
    if (this.writer == null) {
      this.writer = new PrintWriter(new OutputStreamWriter(this.gzipOutputStream, getCharacterEncoding()));
    }
    return this.writer;
  }

  @Override
  public void flushBuffer() throws IOException {
    if (this.writer != null) {
      this.writer.flush();
    }
    if (this.outputStream != null) {
      this.outputStream.flush();
    }
    this.gzipOutputStream.flush();
  }

  public void close() throws IOException {
    this.gzipOutputStream.close();
  }
}
class CustomServletOutputStream extends ServletOutputStream {

  private final GZIPOutputStream gzipOutputStream;

  public CustomServletOutputStream(GZIPOutputStream gzipOutputStream) {
    this.gzipOutputStream = gzipOutputStream;
  }

  @Override
  public boolean isReady() {
    return true;
  }

  @Override
  public void setWriteListener(WriteListener writeListener) {
  }

  @Override
  public void write(int b) throws IOException {
    this.gzipOutputStream.write(b);
  }
}

Finally, use the @ServletComponentScan annotation to automatically scan and configure the filter class with Spring boot.

@SpringBootApplication
@ServletComponentScan
public class App {

  //...
}

3. Testing the Gzip Compression

Once the compression is enabled and configured, the Spring Boot application will automatically compress responses that match the configured MIME types and are larger than the specified minimum response size.

We can use tools like cURL, Postman, or browser developer tools to inspect the HTTP headers of the responses to confirm that Gzip compression is applied.

curl -X GET http://localhost:8080/api/some-endpoint -H "Accept: application/json" -I

Look for the Content-Encoding: gzip header in the response, indicating that Gzip compression was applied.

4. Conclusion

Enabling Gzip compression is a simple and effective way to optimize the performance of your Spring Boot REST API, especially when dealing with large JSON responses or other text-based content.

Drop me your questions related to Gzip compression in Spring Boot.

Happy Learning !!

Weekly Newsletter

Stay Up-to-Date with Our Weekly Updates. Right into Your Inbox.

Comments

Subscribe
Notify of
10 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.