How to Reduce API Payload Size with GZIP Compression in Spring Boot

Learn how to compress large JSON payloads in a Spring Boot advertising API using GZIP, implement a servlet filter and request wrapper to decompress on the server, and evaluate bandwidth, CPU trade‑offs, testing methods, and deployment steps to halve request size.

Programmer DD
Programmer DD
Programmer DD
How to Reduce API Payload Size with GZIP Compression in Spring Boot

1. Business Background

The internal system of the company provides an advertisement saving interface that receives ad data from ADX. An example of the ad data structure is:

adName – the name of the advertisement

adTag – the HTML code of the advertisement, stored as a text field; the largest adTag can be as big as 60KB.

{
    "adName":"",
    "adTag":""
}

Because the request payload can be very large, transmitting it directly brings several drawbacks:

It consumes network bandwidth, which may increase cloud costs.

Large payloads increase transmission time.

To address these issues, the senior team proposed the following idea:

Compress the JSON object string with GZIP before sending it to the advertisement saving interface. The request carries the compressed data, which greatly reduces the transmitted size. On the server side, decompress the data back to a JSON object before processing.

However, this approach also has drawbacks:

The request becomes more complex: the caller must compress the data, and the server must decompress it.

Additional CPU resources are required for compression and decompression.

It may affect existing interfaces.

Given the current business, the following solutions are proposed:

The internal system is I/O‑intensive, so using some CPU cycles to reduce network transmission is worthwhile.

Use a servlet filter to decompress the request body before it reaches the controller, keeping the controller logic unchanged (zero‑intrusion).

Distinguish whether decompression is needed by checking the Content-Encoding=gzip HTTP header.

Now the implementation plan.

2. Implementation Idea

Prerequisite Knowledge

HTTP request structure and the Content-Encoding header

GZIP compression method

Servlet Filter HttpServletRequestWrapper Spring Boot

Java I/O streams

Implementation flowchart:

Core Code

Create a Spring Boot project with a simple controller that receives a JSON object and returns it, simulating the ad‑saving operation.

/**
 * @ClassName ProjectController
 * @Author zhangjin
 * @Date 2022/3/24 20:41
 * @Description:
 */
 @Slf4j
 @RestController
 public class AdvertisingController {
     @PostMapping("/save")
     public Advertising saveProject(@RequestBody Advertising advertising) {
         log.info("获取内容" + advertising);
         return advertising;
     }
 }

**
 * @ClassName Project
 * @Author zhangjin
 * @Date 2022/3/24 20:42
 * @Description:
 */
 @Data
 public class Advertising {
     private String adName;
     private String adTag;
 }

Write and register a GZIP filter.

/**
 * @ClassName GZIPFilter
 * @Author zhangjin
 * @Date 2022/3/26 0:36
 * @Description:
 */
 @Slf4j
 @Component
 public class GZIPFilter implements Filter {

     private static final String CONTENT_ENCODING = "Content-Encoding";
     private static final String CONTENT_ENCODING_TYPE = "gzip";

     @Override
     public void init(FilterConfig filterConfig) throws ServletException {
         log.info("init GZIPFilter");
     }

     @Override
     public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
         long start = System.currentTimeMillis();
         HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;

         String encodeType = httpServletRequest.getHeader(CONTENT_ENCODING);
         if (CONTENT_ENCODING_TYPE.equals(encodeType)) {
             log.info("请求:{} 需要解压", httpServletRequest.getRequestURI());
             UnZIPRequestWrapper unZIPRequestWrapper = new UnZIPRequestWrapper(httpServletRequest);
             filterChain.doFilter(unZIPRequestWrapper, servletResponse);
         } else {
             log.info("请求:{} 无需解压", httpServletRequest.getRequestURI());
             filterChain.doFilter(servletRequest, servletResponse);
         }
         log.info("耗时:{}ms", System.currentTimeMillis() - start);
     }

     @Override
     public void destroy() {
         log.info("destroy GZIPFilter");
     }
 }

**
 * @ClassName FilterRegistration
 * @Author zhangjin
 * @Date 2022/3/26 0:36
 * @Description:
 */
 @Configuration
 public class FilterRegistration {

     @Resource
     private GZIPFilter gzipFilter;

     @Bean
     public FilterRegistrationBean<GZIPFilter> gzipFilterRegistrationBean() {
         FilterRegistrationBean<GZIPFilter> registration = new FilterRegistrationBean<>();
         registration.setFilter(gzipFilter);
         registration.setName("gzipFilter");
         registration.addUrlPatterns("/*");
         registration.setOrder(1);
         return registration;
     }
 }

Implement UnZIPRequestWrapper to decompress the request body and rewrite it.

/**
 * @ClassName UnZIPRequestWrapper
 * @Author zhangjin
 * @Date 2022/3/26 11:02
 * @Description: JsonString compressed to binary -> decompress -> write back to body
 */
 @Slf4j
 public class UnZIPRequestWrapper extends HttpServletRequestWrapper {

     private final byte[] bytes;

     public UnZIPRequestWrapper(HttpServletRequest request) throws IOException {
         super(request);
         try (BufferedInputStream bis = new BufferedInputStream(request.getInputStream());
              ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
             final byte[] body;
             byte[] buffer = new byte[1024];
             int len;
             while ((len = bis.read(buffer)) > 0) {
                 baos.write(buffer, 0, len);
             }
             body = baos.toByteArray();
             if (body.length == 0) {
                 log.info("Body无内容,无需解压");
                 bytes = body;
                 return;
             }
             this.bytes = GZIPUtils.uncompressToByteArray(body);
         } catch (IOException ex) {
             log.info("解压缩步骤发生异常!");
             ex.printStackTrace();
             throw ex;
         }
     }

     @Override
     public ServletInputStream getInputStream() throws IOException {
         final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
         return new ServletInputStream() {
             @Override
             public boolean isFinished() { return false; }
             @Override
             public boolean isReady() { return false; }
             @Override
             public void setReadListener(ReadListener readListener) {}
             @Override
             public int read() throws IOException { return byteArrayInputStream.read(); }
         };
     }

     @Override
     public BufferedReader getReader() throws IOException {
         return new BufferedReader(new InputStreamReader(this.getInputStream()));
     }
 }

Utility class GZIPUtils for compression and decompression.

public class GZIPUtils {

    public static final String GZIP_ENCODE_UTF_8 = "UTF-8";

    /** string compress to GZIP byte array */
    public static byte[] compress(String str) {
        return compress(str, GZIP_ENCODE_UTF_8);
    }

    public static byte[] compress(String str, String encoding) {
        if (str == null || str.length() == 0) {
            return null;
        }
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        try {
            GZIPOutputStream gzip = new GZIPOutputStream(out);
            gzip.write(str.getBytes(encoding));
            gzip.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return out.toByteArray();
    }

    /** GZIP decompress */
    public static byte[] uncompress(byte[] bytes) {
        if (bytes == null || bytes.length == 0) {
            return null;
        }
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        ByteArrayInputStream in = new ByteArrayInputStream(bytes);
        try {
            GZIPInputStream ungzip = new GZIPInputStream(in);
            byte[] buffer = new byte[256];
            int n;
            while ((n = ungzip.read(buffer)) >= 0) {
                out.write(buffer, 0, n);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return out.toByteArray();
    }

    public static String uncompressToString(byte[] bytes) throws IOException {
        return uncompressToString(bytes, GZIP_ENCODE_UTF_8);
    }

    public static String uncompressToString(byte[] bytes, String encoding) throws IOException {
        byte[] result = uncompressToByteArray(bytes, encoding);
        return new String(result);
    }

    public static byte[] uncompressToByteArray(byte[] bytes) throws IOException {
        return uncompressToByteArray(bytes, GZIP_ENCODE_UTF_8);
    }

    public static byte[] uncompressToByteArray(byte[] bytes, String encoding) throws IOException {
        if (bytes == null || bytes.length == 0) {
            return null;
        }
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        ByteArrayInputStream in = new ByteArrayInputStream(bytes);
        try {
            GZIPInputStream ungzip = new GZIPInputStream(in);
            byte[] buffer = new byte[256];
            int n;
            while ((n = ungzip.read(buffer)) >= 0) {
                out.write(buffer, 0, n);
            }
            return out.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
            throw new IOException("解压缩失败!");
        }
    }

    public static void saveFile(String filename, byte[] data) throws Exception {
        if (data != null) {
            String filepath = "/" + filename;
            File file = new File(filepath);
            if (file.exists()) {
                file.delete();
            }
            FileOutputStream fos = new FileOutputStream(file);
            fos.write(data, 0, data.length);
            fos.flush();
            fos.close();
            System.out.println(file);
        }
    }
}

3. Test Effect

Important pitfall: do not treat the compressed byte[] as a string for transmission, otherwise the size may become larger than the original. Two common ways to transmit compressed data are:

Base64‑encode the compressed byte[] and send it as a string (some compression loss, suitable for storing in Redis).

Write the compressed byte[] as a binary file and send the file in the request body (no compression loss).

Postman test for GZIP compressed request:

Set the request header to indicate the compression method.

Include the binary file containing the compressed byte[] in the request body.

Execute the request; the server correctly processes it and the request size is reduced by nearly half.

4. Demo Address

https://gitee.com/wx_1bceb446a4/gziptest

Thank you for reading, hope it helps :)
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaSpring BootgzipServlet FilterHTTP Compression
Programmer DD
Written by

Programmer DD

A tinkering programmer and author of "Spring Cloud Microservices in Action"

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.