how to selectively disable cache for spring boot (manifest.appcache)
Asked Answered
B

3

5

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);
        }
    }
Berton answered 6/10, 2014 at 12:58 Comment(5)
Just adding a class extending WebMvcConfigurerAdapter and adding a specific rule for that resource should do the trick.Enforce
I tried this: @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { super.addResourceHandlers(registry); registry.addResourceHandler("/manifest.appcache").addResourceLocations("/").setCachePeriod(0); } but i get a 404.Berton
Using / will make it try to retrieve from the root of the web application. Make sure that the / covers the correct physical location of the file.Enforce
my manifest.appcache lives in the root of the app (in this case /public, which is the same location index.html lives.Berton
Then it should be /public not /.Enforce
R
2

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:

  1. 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).

  2. 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
Reboant answered 21/9, 2015 at 12:53 Comment(1)
solid answer, thanks. for your first point it's not the rev that's changing anything, the browser is looking at the comments and hashing it. if it detects a change in the hash it invalidates the cache and reloads. for your second point, that's definitely the preferred solution since it targets the appcache exclusively and doesn't disturb the other cache periods. i'll mark your answer as the preferred one.Berton
B
4

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.

Berton answered 19/2, 2015 at 13:34 Comment(0)
R
2

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:

  1. 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).

  2. 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
Reboant answered 21/9, 2015 at 12:53 Comment(1)
solid answer, thanks. for your first point it's not the rev that's changing anything, the browser is looking at the comments and hashing it. if it detects a change in the hash it invalidates the cache and reloads. for your second point, that's definitely the preferred solution since it targets the appcache exclusively and doesn't disturb the other cache periods. i'll mark your answer as the preferred one.Berton
A
2

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

Alexina answered 25/2, 2016 at 23:19 Comment(2)
Don't forget to add spring.resources.cache-period=3600 with the time to expire in seconds.Hoseahoseia
added the answer here. pages don't load now.Squadron

© 2022 - 2024 — McMap. All rights reserved.