Reputation: 727
I have some javascript bundled file that is pretty big, ~1MB. I'm trying to turn on response compression with the following application properties in my yml file:
server.compression.enabled: true
server.compression.mime-types: application/json,application/xml,text/html,text/xml,text/plain,application/javascript,text/css
But it doesn't work. No compression is happening.
Request headers:
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36
Accept: */*
Accept-Encoding: gzip, deflate, sdch, br
Response headers
Cache-Control:no-cache, no-store, max-age=0, must-revalidate
Connection:keep-alive
Content-Length:842821
Content-Type:application/javascript;charset=UTF-8
There's no content encoding header in the response.
I'm using spring boot version 1.3.5.RELEASE
What am I missing?
=== EDIT 4 === I was planning to create a stand alone app to investigate further why content compression properties weren't working. But all of sudden it started working and I haven't changed any thing configuration-wise, not POM file change, not application.yml file change. So I don't know what has changed that made it working...
===EDIT 3=== follow @chimmi's suggestions further. I've put break points in the suggested places. It looks like requests to static resources (js files) never stopped at those break points. Only rest API requests do. And for those request, the content-length was zero for some reason which causes the content compression to be skipped.
===EDIT 2=== I've put a break point at line 180 of o.s.b.a.w.ServerProperties thanks to @chimmi's suggestion and it shows that all the properties are set but somehow the server doesn't honor the setting... :(
===EDIT 1===
not sure if it matters, but I'm pasting my application main and configuration code here:
Application.java:
@SpringBootApplication
public class TuangouApplication extends SpringBootServletInitializer {
public static void main(String[] args) throws Exception {
SpringApplication.run(TuangouApplication.class, args);
}
// this is for WAR file deployment
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(TuangouApplication.class);
}
@Bean
public javax.validation.Validator localValidatorFactoryBean() {
return new LocalValidatorFactoryBean();
}
}
Configuration:
@Configuration
public class TuangouConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http.antMatcher("/**").authorizeRequests().antMatchers("/", "/login**").permitAll()
.and().antMatcher("/**").authorizeRequests().antMatchers("/api/**").permitAll()
.and().exceptionHandling().authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/"))
.and().formLogin().loginPage("/login").failureUrl("/login?error").permitAll()
.and().logout().logoutSuccessUrl("/").permitAll()
.and().csrf().csrfTokenRepository(csrfTokenRepository())
.and().addFilterAfter(csrfHeaderFilter(), CsrfFilter.class)
.headers().defaultsDisabled().cacheControl();
// @formatter:on
}
@Order(Ordered.HIGHEST_PRECEDENCE)
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled=true)
protected static class AuthenticationSecurity extends GlobalAuthenticationConfigurerAdapter {
@Override
public void init(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService()).passwordEncoder(new BCryptPasswordEncoder());
}
@Bean
public UserDetailsService userDetailsService() {
return new DatabaseUserServiceDetails();
}
}
private Filter csrfHeaderFilter() {
return new OncePerRequestFilter() {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
CsrfToken csrf = (CsrfToken) request
.getAttribute(CsrfToken.class.getName());
if (csrf != null) {
Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
String token = csrf.getToken();
if (cookie == null
|| token != null && !token.equals(cookie.getValue())) {
cookie = new Cookie("XSRF-TOKEN", token);
cookie.setPath("/");
response.addCookie(cookie);
}
}
filterChain.doFilter(request, response);
}
};
}
private CsrfTokenRepository csrfTokenRepository() {
HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
repository.setHeaderName("X-XSRF-TOKEN");
return repository;
}
}
Resource server config:
@Configuration
@EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter{
@Autowired
private TokenStore tokenStore;
@Override
public void configure(ResourceServerSecurityConfigurer resources)
throws Exception {
resources.tokenStore(tokenStore);
}
@Override
public void configure(HttpSecurity http) throws Exception {
// @formatter:off
http.antMatcher("/**").authorizeRequests().antMatchers("/api/**").permitAll();
// @formatter:on
}
}
Upvotes: 28
Views: 24823
Reputation: 493
I ran into the same issue and spent many hours stepping through Apache and Spring code around this. I finally tracked it down to org.apache.coyote.CompressionConfig::useCompression()
and found something surprising. If you're generating ETags and they're strong (that is, they don't start with W/) then compression is disabled.
I'm using Spring's ShallowEtagHeaderFilter
, which. by default, generates strong ETags. My fix was to change that via setWriteWeakETag(true)
.
Upvotes: 1
Reputation: 874
When upgrading to Spring Boot 2.6 I had to add the following to my application.yml
to allow static resources to be compressed:
spring:
web:
resources:
chain:
compressed: true
The server.compression
settings seem not to impact this.
Upvotes: 2
Reputation: 405
I was having the same issue on production. My configuration file is as follows:
server:
port: 8080
compression:
enabled: true
mime-types: text/html,text/xml,text/plain,text/css, application/javascript, application/json
min-response-size: 1024
Since i was not using the Embedded tomcat, I had to enable compression on the Tomcat itself by editing the following section of the server.xml
file:
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" compression="on"/>
Make sure that this section has the compression="on"
part and the issue should be resolved
Upvotes: 1
Reputation: 93
you have to enable ssl like http2 mode, response compression (Content-Encoding) can work, when ssl mode is configured.
application.yml
server:
compression:
enabled: true
mime-types: text/html,text/xml,text/plain,text/css, application/javascript, application/json
min-response-size: 1024
ssl:
enabled: true
key-store: keystore.p12
key-store-password: pass
keyStoreType: PKCS12
keyAlias: name
spring:
resources:
chain:
gzipped: true
Upvotes: 1
Reputation: 9855
Never had much luck with the Spring Boot compression. A simple solution could be to use a third party library like ziplet.
Add to pom.xml
<dependency>
<groupId>com.github.ziplet</groupId>
<artifactId>ziplet</artifactId>
<version>2.0.0</version>
<exclusions>
<exclusion>
<artifactId>servlet-api</artifactId>
<groupId>javax.servlet</groupId>
</exclusion>
</exclusions>
</dependency>
Add to your @Config class :
@Bean
public Filter compressingFilter() {
return new CompressingFilter();
}
Upvotes: 5
Reputation: 15297
Did you try with different browsers? That could be because of antivirus which is unzipping the file as mentioned in the SO post Spring boot http response compression doesn't work for some User-Agents
Upvotes: 1
Reputation: 327
Maybe the problem is with YAML configuration.
If you use ‘Starters’ SnakeYAML will be automatically provided via spring-boot-starter
. If you don't - you must use properties convention in application.properties.
Using YAML instead of Properties
EDIT: Try with this in your yml file:
server:
compression:
enabled: true
mime-types: text/html,text/xml,text/plain,text/css,application/javascript,application/json
min-response-size: 1024
Upvotes: 7
Reputation: 327
If you use non-embedded Tomcat you should add this to your server.xml:
compression="on"
compressionMinSize="2048"
compressableMimeType="text/html,text/xml,application/javascript"
More tomcat 8 config variables
Upvotes: 2