14

I am using Spring Boot 1.5.10.RELEASE version. Gzip compress not working.

http://localhost:9000 --> http://localhost:8080/api/..

Angularjs & rest api on different Port. Enabled CrossOrigin to accept request from angularjs ui.

Using embedded tomcat server to deploy spring boot application. Not using http2 property i.e. server.http2.enabled=true

Angualrjs calls rest api. Following is $http service

$http({
  method: method,
  url: url,
  params: params,
  data: body,
  headers: {
    Authorization: token,
    "Content-type": 'application/json'
  }
});

Rest api response size Approx 25 MB so I want to compress response.

I have added well known property in application.properties to apply gzip compression. Spring boot 1.5.10 Supported properties

# Enable response compression
server.compression.enabled=true

# The comma-separated list of mime types that should be compressed
server.compression.mime-types=text/html,text/xml,text/plain,text/css,text/javascript,application/javascript,application/json

# Compress the response only if the response size is at least 1KB
server.compression.min-response-size=1024

I have observed network tab and no observed Content-Encoding: gzip in response header.

Request

Request URL: http://localhost:9081/employee
Request Method: GET
Status Code: 200 
Remote Address: [::1]:9081
Referrer Policy: no-referrer-when-downgrade

Response Header

Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: http://localhost:7000
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Type: application/json;charset=UTF-8
Date: Sun, 28 Jun 2020 18:15:17 GMT
Expires: 0
Pragma: no-cache
Set-Cookie: JSESSIONID=6E7C07874D0329E18A0C07E5E303F005; Path=/; HttpOnly
Transfer-Encoding: chunked
Vary: Origin
X-Application-Context: application
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block

Request Header

Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Authorization: Bearer eyJhbGciOiJIUzINiJ9.eyJyb2xlIjiU0VDVE9SSEVBRCIsImxldmVsRG93biI6IkVENzA0MTI7TU04MzcyNDtKTDgzNTwO0RNNDAwNzE7Skc3MzA0NjtFQzM0NjEzO05OMTY5Nzk7QUs2MDYzNztTVDE4NTg4O0FTMjczNTE7Q0I4MTg3OTtWQTc4MTk5O0NNOTM3MDA7QVkyMzYzNztKUzcwMDY4O0NCMTc2NzE7TksyMTU2MDtMUzg4OTg0O0FQNTg3MDg7VFcyjk0NTtKSzI1Nzc3O01TNDk5MjE7SkI4OTcyOTtNSDAyMTI3O01CMTUwODk7SU0xMjgwODtNQzcxOTc2O1JSMjAzMDI7TFM1ODk4MiIsImxldmVsVXAiOm51bGwsImRlbGVnYXRlZCI6bnVsbCwic29lSWQiOiJTUjQ0MTg1I0.*************
Cache-Control: no-cache
Connection: keep-alive
Content-type: application/json
Host: localhost:9081
Origin: http://localhost:7000
Pragma: no-cache
Referer: http://localhost:7000/build/standalone.html
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36

I am not getting following expected headers in response header

Content-Encoding: gzip
Vary: Accept-Encoding

Any changes require at client /server side ?

---[Edit-1] ------------- Tried gzip in individual project which worked but not worked in my project.

Following is response header when invoke rest api from browser

Content-Encoding: gzip
Content-Type: application/json;charset=UTF-8
Date: Sun, 28 Jun 2020 18:12:29 GMT
Transfer-Encoding: chunked
Vary: Accept-Encoding

-----[Edit-2]-----Ziplet----

Using ziplet dependency I am able to compress response, but I want to use spring boot gzip compression.

Response header - when used Ziplet

Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: http://localhost:7000
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Encoding: gzip
Content-Type: application/json;charset=UTF-8
Date: Mon, 06 Jul 2020 18:31:07 GMT
Expires: 0
Pragma: no-cache
Set-Cookie: JSESSIONID=8465D2E81A1A9CE146255B6C545FBE30; Path=/; HttpOnly
Transfer-Encoding: chunked
Vary: Accept-Encoding
Vary: Origin
X-Application-Context: application
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block

When used ziplet - I can see CompressingFilter : CompressingFilter has initialized

When using Spring boot gzip compression not observed anything where I can assume gzip compression enabled.

Any property to debug spring boot gzip compression with embeded tomcat ? like logging.level.org.eclipse.jetty.server.handler.gzip=TRACE

How can i verify server.compression.enabled ?

Any changes require at client /server side in my project?

Thanks in advance.

StackOverFlow
  • 4,486
  • 12
  • 52
  • 87
  • i tried ziplet 3rd party library - https://stackoverflow.com/a/39027711/297907 Ziplet compressing response and observed "Content-Encoding: gzip" "Vary: Accept-Encoding". I would like to use spring boot gzip compression – StackOverFlow Jun 29 '20 at 11:53
  • Put your code repository for testing. – Anish B. Jul 01 '20 at 09:36
  • I think your problem is detailed here https://github.com/spring-projects/spring-boot/issues/18484 – Dan M Jul 01 '20 at 17:57
  • This could be due to the content-type. `application/json` is not `application/json;charset=UTF-8`. Could be that tomcat (the embedded server) is interpreting that wrongly, but you would have to dive into tomcat then (or simply remove the charset from the response, although it might be that Spring is adding that). – M. Deinum Jul 02 '20 at 05:57
  • @M. Deinum "Content-Type: application/json;charset=UTF-8" is not issue, I am confident on that as my individual app gz response is gzip and observed same Content-Type. – StackOverFlow Jul 02 '20 at 16:00
  • 2
    That was using a filter and not relying on the tomcat support (if I read your question correctly) so you are basically comparing 2 different mechanisms. – M. Deinum Jul 02 '20 at 17:22
  • @M. Deinum - Yes, charset=utf-8 might be appended by spring. I tried with server.compression.mime-types=application/json;charset=UTF-8 but no luck – StackOverFlow Jul 06 '20 at 18:46
  • @JamesMead I am using embeded tomcat. I have update more information in question – StackOverFlow Jul 06 '20 at 19:12
  • So the way we are handling gzip in our spring boot application is we have a compression filter which when sees a request is received with Accept-Encoding gzip, we set the response header content-encoding as gzip and wraps the response object into a CompressionResponseWrapper which is passed to the filter chain. Ofcourse if the request does not come with the header we do not wrap it up and chain it as is. I'll not be able to share code due to restrictions but give you reference to some examples on the internet – Vivek Jul 06 '20 at 20:14
  • Is the `Accept-Encoding` header being passed to Spring Boot? You are using a proxy in between your angular stuff and Spring Boot, make sure that that doesn't filter stuff out. Try with a direct call to Spring Boot instead of through the proxy (using postman for instance). – M. Deinum Jul 07 '20 at 06:55
  • @M. Deinum No - I am not passing Accept-Encoding header in ajax call , browser adding "Accept-Encoding: gzip, deflate, br". let me try with postman. – StackOverFlow Jul 07 '20 at 08:49
  • I nowhere said you should post in in your AJAX call but if the proxy you are using is passing that header along!. – M. Deinum Jul 07 '20 at 08:54

2 Answers2

3

As your question, you are using Spring Boot 1.5.10.RELEASE.

For that version of the framework, the class TomcatEmbeddedServletContainerFactory is responsible for starting the embedded Tomcat container.

The source code of that class and version can be found here:

https://github.com/spring-projects/spring-boot/blob/v1.5.10.RELEASE/spring-boot/src/main/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainerFactory.java

In this class, you can find the method customizeCompression:

private void customizeCompression(Connector connector) {
  ProtocolHandler handler = connector.getProtocolHandler();
  if (handler instanceof AbstractHttp11Protocol) {
    AbstractHttp11Protocol<?> protocol = (AbstractHttp11Protocol<?>) handler;
    Compression compression = getCompression();
    protocol.setCompression("on");
    protocol.setCompressionMinSize(compression.getMinResponseSize());
    configureCompressibleMimeTypes(protocol, compression);
    if (getCompression().getExcludedUserAgents() != null) {
      protocol.setNoCompressionUserAgents(
          StringUtils.arrayToCommaDelimitedString(
              getCompression().getExcludedUserAgents()));
    }
  }
}

Try setting a breakpoint on this method and debug your application to see if compression is actually enabled.

If not, it is very likely that there is some kind of wrong configuration in your project.

If it works, it indicates that your configuration is correct and that the problem is different.

If this is the case, before looking at anything else, it might be appropriate to try another server, such as Jetty or Undertow, which also support this compression feature, and see if everything works correctly there.

For instance, to configure Undertow instead of Tomcat you can use the following:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-undertow</artifactId>
</dependency>

You can try to configure Tomcat compression programmatically as well; see matsev's answer in this stackoverflow question:

Using GZIP compression with Spring Boot/MVC/JavaConfig with RESTful

jccampanero
  • 50,989
  • 3
  • 20
  • 49
-1

You have to enable http2 support in your spring boot properties

  server.http2.enabled=true

And then try

Vishal Varshney
  • 105
  • 1
  • 8
  • 2
    This is more of a comment than an answer. Can you elaborate on why would gzip compression require http2? I believe there's been gzip compression long before http2 existed, so that point is not clear. – Edwin Dalorzo Jul 14 '20 at 14:57
  • oh.. My bad I misread that, I thought in the question it is mentioned to use http2 – Vishal Varshney Jul 14 '20 at 16:33