Gzip is a compression encoding format. The server often compresses the response body by this encoding and then responds to the client, thus reducing the data size, increasing the transmission speed and saving bandwidth. The client then decompresses it by Gzip to get the original data. It consumes extra CPU resources because of the compression computation required.

Http Header & Encoding

There are many other ways to encode similar to Gzip. The client and server need to negotiate to determine the encoding method to be used(Some clients do not support Gzip).

Content-Encoding

This is a response header, and the MDN explains it as follows.

The Content-Encoding representation header lists any encodings that have been applied to the representation (message payload), and in what order. This lets the recipient know how to decode the representation in order to obtain the original payload format. Content encoding is mainly used to compress the message data without losing information about the origin media type.

Note that the original media/content type is specified in the Content-Type header, and that the Content-Encoding applies to the representation, or “coded form”, of the data. If the original media is encoded in some way (e.g. a zip file) then this information would not be included in the Content-Encoding header.

Servers are encouraged to compress data as much as possible, and should use content encoding where appropriate. Compressing a compressed media type such as a zip or jpeg may not be appropriate, as this can make the payload larger.

The common understanding is that the server tells the client through this Header what type of encoding is used in the response body.

Accept-Encoding

This is a request header and the MDN is explained below.

The Accept-Encoding request HTTP header indicates the content encoding (usually a compression algorithm) that the client can understand. The server uses content negotiation to select one of the proposals and informs the client of that choice with the Content-Encoding response header.

Even if both the client and the server support the same compression algorithms, the server may choose not to compress the body of a response if the identity value is also acceptable. Two common cases lead to this:

  • The data to be sent is already compressed, therefore a second compression will not reduce the transmitted data size. This is true for pre-compressed image formats (JPEG, for instance);
  • The server is overloaded and cannot allocate computing resources to perform the compression. For example, Microsoft recommends not to compress if a server uses more than 80% of its computational power.

As long as the identity;q=0 or *;q=0 directives do not explicitly forbid the identity value that means no encoding, the server must never return a 406 Not Acceptable error.

The client uses this request header to tell the server the list of encoding types it accepts, from which the server typically selects one to encode the response body.

Server encoding response body

 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
package io.springcloud.demo.web.controller;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.zip.GZIPOutputStream;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/test")
public class TestController {

    @GetMapping
    public void test(HttpServletRequest request, HttpServletResponse reponse) throws IOException {

        // Response Body
        String content = "Hello Spring Cloud";

        // Encoding types supported by the client
        String acceptEncooding = request.getHeader(HttpHeaders.ACCEPT_ENCODING);
        
        // It is assumed that the client only supports the GZIP encoding type.
        acceptEncooding = "gzip";

        // The response body is encoded using gzip
        reponse.setHeader(HttpHeaders.CONTENT_ENCODING, acceptEncooding);
        reponse.setContentType(MediaType.TEXT_PLAIN_VALUE);
        reponse.setCharacterEncoding(StandardCharsets.UTF_8.displayName());
        
        // Response to the client after compression using Gzip
        try (GZIPOutputStream gzipOutputStream = new GZIPOutputStream(reponse.getOutputStream())) {
            gzipOutputStream.write(content.getBytes(StandardCharsets.UTF_8));
            gzipOutputStream.finish();
        }
    }
}

Using the browser to request this Controller, we will get the following response.

1
2
3
4
5
6
7
8
HTTP/1.1 200 OK
Content-Encoding: gzip
Connection: keep-alive
Content-Type: text/plain;charset=UTF-8
Content-Length: 38
Date: Mon, 02 May 2022 10:29:30 GMT
 
Hello Spring Cloud

As you can see, the client automatically decodes the response according to the gzip encoding specified by Content-Encoding. Since the response itself is so small, using GZIP to compress it increases its size.

RestTemplate decoding response body

 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
package io.springcloud.demo.test;

import java.io.ByteArrayOutputStream;
import java.nio.charset.StandardCharsets;
import java.util.zip.GZIPInputStream;

import org.springframework.core.io.Resource;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

public class MainTest {

    public static void main(String[] args) throws Exception {

        RestTemplate restTemplate = new RestTemplate();

        HttpHeaders httpHeaders = new HttpHeaders();

        httpHeaders.set(HttpHeaders.ACCEPT_ENCODING, "gzip");

        ResponseEntity<Resource> responseEntity = restTemplate.exchange("http://localhost/test", HttpMethod.GET,
                new HttpEntity<>(httpHeaders), Resource.class);

        if (!responseEntity.getStatusCode().is2xxSuccessful()) {
            System.err.println("error: " + responseEntity.getStatusCode().getReasonPhrase());
            return;
        }

        // Encoding type of the response body
        String contentEncoding = responseEntity.getHeaders().getFirst(HttpHeaders.CONTENT_ENCODING);

        if ("gzip".equalsIgnoreCase(contentEncoding)) {

            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();

            try (GZIPInputStream gzipInputStream = new GZIPInputStream(responseEntity.getBody().getInputStream())) {
                gzipInputStream.transferTo(byteArrayOutputStream);
            }

            byte[] content = byteArrayOutputStream.toByteArray();

            System.out.println("response: " + new String(content, StandardCharsets.UTF_8));
        } else {
            // TODO
        }
    }
}

The output of the console after running the test code:

1
response: Hello Spring Cloud

If you find that the response data you read via RestTemplate is incorrect. Then you can check if the server is using a certain encoding through the Content-Encoding response header and you need to decode it manually.

SpringBoot Application

If you are using springboot to develop web applications, you can enable response compression (the server will automatically negotiate with the client on the encoding of the compression) by configuring the following.

Name Description Default Value
server.compression.enabled Whether response compression is enabled. false
server.compression.excluded-user-agents Comma-separated list of user agents for which responses should not be compressed.
server.compression.mime-types Comma-separated list of MIME types that should be compressed. [text/html, text/xml, text/plain, text/css, text/javascript, application/javascript, application/json, application/xml]
server.compression.min-response-size Minimum “Content-Length” value that is required for compression to be performed. 2KB