From this question it shows that spring security manages cache for spring boot. From the spring boot documentation it shows how to set cache for resources using:
spring.resources.cache-period= # cache timeouts in headers sent to browser
The cache-period
is great for all the predefined static locations for spring boot (i.e. /css**
, /js/**
, /images/**
) but I'm also generating a manifest.appcache
for offline downloading of my static assets and due to all the above spring security/boot sends back cache headers with the manifest.appcache
"method": "GET",
"path": "/manifest.appcache",
"response": {
"X-Application-Context": "application:local,flyway,oracle,kerberos:8080",
"Expires": "Tue, 06 Oct 2015 16:59:39 GMT",
"Cache-Control": "max-age=31556926, must-revalidate",
"status": "304"
}
I'd like to know how to add an exclusion for manifest.appcache
. IE and Chrome seem to 'do the right thing' with appcache regardless of my headers, but FF seems to be a little more peculiar in noting when the appcache has changed and I'm thinking my cache headers are screwing it up.
EDIT:
I should add from the source for WebMvcAutoConfiguration it shows how the cache is setup for the resources, I'm just unsure how to selectively disable for my 1 case w/o potentially disrupting the rest of what spring boot sets up in this file.
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
return;
}
Integer cachePeriod = this.resourceProperties.getCachePeriod();
if (!registry.hasMappingForPattern("/webjars/**")) {
registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/")
.setCachePeriod(cachePeriod);
}
if (!registry.hasMappingForPattern("/**")) {
registry.addResourceHandler("/**")
.addResourceLocations(RESOURCE_LOCATIONS)
.setCachePeriod(cachePeriod);
}
}
Thanks for the Q and the A!
We had similar problems: All browsers (Chrome, Safari, IE) but one (FF) didn't cache the manifest files themselves but reloaded it after a change.
However, setting the cache period setting in Spring Boot didn't solve the problem completely. Additionally I didn't want to set cache-control parameters for all files served by the Spring Boot application, but only to disable caching for the manifest.
My solution consists of of two parts:
Provide a "rev" comment in the Manifest file. Though not covered by the W3C spec some browsers seem to want a comment like this to detect changes in the manifest or the referenced (cached) files:
# rev 7
We now change the "rev" parameter in the cache manifest file by a Maven generated unique build number: https://github.com/dukecon/dukecon_html5/commit/b60298f0b856a7e54c97620f278982142e3e1f45).
- Disable caching by providing a Filter which adds a header "Cache-Control: no-cache" to exactly the cache.manifest file pattern: https://github.com/dukecon/dukecon_server/commit/dc02f26996cb172df804da007546f439df75126d
Based on this answer detailing IE needing "max-age=1, must-revalidate", and through testing on all browsers, setting a properties value of
spring.resources.cache-period=1
will allow the proper http headers to be written which allow the appcache manifest to be handled properly. it's not the solution I hoped for (being able to have a cache-period of 0 with proper headers is what i wanted) but it does make the browser perform properly and utilize the appcache manifest properly.
Again to summarize the solution context - this is for my app that downloads all my assets offline (js/css/html) and serves from appcache.
In current version (Feb 2016) there is no need to do something in code to change default behavior.
Just do some configuration in your application.properties:
# Enable HTML5 application cache manifest rewriting.
spring.resources.chain.html-application-cache=true
# Enable the Spring Resource Handling chain. Disabled by default unless at least one strategy has been enabled.
spring.resources.chain.enabled=true
# Enable the content Version Strategy.
spring.resources.chain.strategy.content.enabled=true
# Comma-separated list of patterns to apply to the Version Strategy.
spring.resources.chain.strategy.content.paths=/**
# Locations of static resources.
spring.resources.static-locations=classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/
That's all. Now Spring will check if your static files was changed and can send smarter responses (If-Modiffied-Since and others) and rewrite your appcache also.
Also, if there are reasons to not use content-based version for some resources - you can use alternate FixedVersion strategy and set version explicitly in your config:
#Enable the fixed Version Strategy.
spring.resources.chain.strategy.fixed.enabled=false
# Comma-separated list of patterns to apply to the Version Strategy.
spring.resources.chain.strategy.fixed.paths=
# Version string to use for the Version Strategy.
spring.resources.chain.strategy.fixed.version=
P.S. Don't forget about Spring Security: it rewrite cache headers and disable caching.
See more in docs