Automatic HTTP Request Body Decompression in Spring Microservices
In a Spring microservices, it’s common to send and receive data in JSON format. JSON is a text-based format, which means that it can be compressed to reduce the size of HTTP requests and responses. One common compression format is gzip, which can significantly reduce the size of JSON data. In this article, we’ll explore how to enable automatic gzip decompression of HTTP request bodies in a Spring microservice.
What is Gzip Compression?
Gzip is a popular compression format used in HTTP to compress the size of data being transferred. Gzip works by compressing the data using the DEFLATE algorithm and then adding a gzip header and footer to the compressed data. When a client sends an HTTP request with the “Content-Encoding: gzip” header, it’s indicating that the request body is compressed using gzip. The server can then automatically decompress the request body before processing it.
Enabling Automatic Gzip Decompression in Spring Microservices
To enable automatic gzip decompression in a Spring microservice, you can follow these steps:
- Add the
spring-boot-starter-web
dependency to yourpom.xml
file if you haven’t already:
1 2 3 4 5 6 7 |
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> |
2. Add the following properties to your application.properties
file:
1 2 3 4 5 6 |
server.compression.enabled=true server.compression.mime-types=application/json,application/xml,text/plain,text/html server.compression.min-response-size=1024 |
These properties enable compression for the specified MIME types and response sizes.
3. Create a custom Filter
that decompresses the request body. Here’s an example of what the filter might look like:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import org.springframework.web.filter.OncePerRequestFilter; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.zip.GZIPInputStream; @Component @Order(1) public class GzipDecompressingFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { if (request.getHeader("Content-Encoding") != null && request.getHeader("Content-Encoding").contains("gzip")) { request = new GzipHttpServletRequestWrapper(request); } filterChain.doFilter(request, response); } private static class GzipHttpServletRequestWrapper extends HttpServletRequestWrapper { public GzipHttpServletRequestWrapper(HttpServletRequest request) throws IOException { super(request); } @Override public ServletInputStream getInputStream() throws IOException { return new GzipServletInputStreamWrapper(new GZIPInputStream(super.getInputStream())); } } private static class GzipServletInputStreamWrapper extends ServletInputStream { private final InputStream delegate; public GzipServletInputStreamWrapper(InputStream delegate) { this.delegate = delegate; } @Override public int read() throws IOException { return delegate.read(); } @Override public void close() throws IOException { delegate.close(); } } } |
This filter checks if the Content-Encoding
header contains gzip
, and if so, wraps the request with a GzipHttpServletRequestWrapper
that decompresses the request body.
4. Register the filter by creating a FilterRegistrationBean
in your Spring Boot application class. Here’s an example of what the bean might look like:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class AppConfig { @Bean public FilterRegistrationBean<GzipDecompressingFilter> gzipDecompressingFilterRegistration() { FilterRegistrationBean<GzipDecompressingFilter> registration = new FilterRegistrationBean<>(); registration.setFilter(new GzipDecompressingFilter()); registration.addUrlPatterns("/*"); return registration; } } |
This configuration creates a FilterRegistrationBean
that registers the GzipDecompressingFilter
for all URL patterns.
- Write a controller method that accepts a JSON request body. Here’s an example of what the method might look like:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; @RestController public class UserController { @PostMapping("/api/users") public ResponseEntity<Void> createUser(@RequestBody User user) { // code to create user return new ResponseEntity<>(HttpStatus.CREATED); } } |
This assumes that you have a User
class with appropriate fields and constructors.
6. Test the automatic request body gzip decompression by sending a gzipped request to your endpoint. For example, using curl
:
1 2 3 4 |
curl -X POST -H "Content-Encoding: gzip" --data-binary @user.json.gz http://localhost:8080/api/users |
This sends a gzipped user.json
file as the request body to the /api/users
endpoint.If everything is working correctly, the createUser
method should receive a deserialized User
object, and you should see a response from the server indicating that the user was created.
Conclusion
Enabling automatic request body gzip decompression in Spring microservices can significantly reduce the size of HTTP requests and responses. By following the steps outlined in this article, you can easily enable automatic gzip decompression in your Spring microservice.