how to selectively disable cache for spring boot (

2019-04-10 13:50发布

问题:

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);
        }
    }

回答1:

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


回答2:

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.



回答3:

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