Sofia Pahaoja
Sofia Pahaoja

Reputation: 2720

How to enable HTTP caching for the resource handler with Spring MVC and Spring Security

I wish to enable HTTP caching for some static resources such as images, for which access is restricted by Spring Security. (These resources are not security critical, but shouldn't be publicly accessible either). How do I avoid having Spring Security add HTTP response headers that disable caching?

If I add setCachePeriod() into my resource handler registration in WebMvcConfigurerAdapter.addResourceHandlers() as following:

registry.addResourceHandler("/static/**")
  .addResourceLocations("classpath:/static/").setCachePeriod(3600);

The resources are still returned with following headers that disable caching:

Cache-Control: max-age=3600, must-revalidate
Expires: Mon, 04 Aug 2014 07:45:36 GMT
Pragma: no-cache

I want to avoid introducing any XML configuration into the project, which currently uses only Java annotation configuration.

Are there better solutions than extending the Spring resource handler?

Upvotes: 11

Views: 12013

Answers (4)

sschrass
sschrass

Reputation: 7156

For Spring-Boot 3.3.4 (Spring Core 6.1.13) I went with:

spring.web.resources.chain.strategy.content.enabled=true
spring.web.resources.cache.cachecontrol.max-age=31536000

What caches images, css, and js (webjars were already cached autmatically) by their content hashes.

Upvotes: 0

SunilGiri
SunilGiri

Reputation: 71

Spring 4 documentation has this solution, "If you actually want to cache specific responses, your application can selectively invoke HttpServletResponse.setHeader(String,String) to override the header set by Spring Security". This is useful to ensure things like CSS, JavaScript, and images are properly cached.

Below snippet can be used for springmvc configuration,

@EnableWebMvc
public class WebMvcConfiguration extends WebMvcConfigurerAdapter {

  @Override
  public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry
        .addResourceHandler("/resources/**")
        .addResourceLocations("/resources/")
        .setCachePeriod(31556926);
  }

// ...
}

For reference: http://docs.spring.io/spring-security/site/docs/4.0.0.CI-SNAPSHOT/reference/htmlsingle/#headers-cache-control

Upvotes: 1

JimB
JimB

Reputation: 1153

You are already setup for caching. must-revalidate means once the cache expires (3600 seconds) do not use it anymore so your response headers, i think, are correct for what you want.

Upvotes: 0

Jeevan Patil
Jeevan Patil

Reputation: 6079

You can use webContentInterceptor resource to allow static resource caching.

<mvc:interceptors>
    <mvc:interceptor>
    <mvc:mapping path="/static/*"/>
        <bean id="webContentInterceptor" class="org.springframework.web.servlet.mvc.WebContentInterceptor">
            <property name="cacheSeconds" value="31556926"/>
            <property name="useExpiresHeader" value="true"/>
            <property name="useCacheControlHeader" value="true"/>
            <property name="useCacheControlNoStore" value="true"/>
        </bean>
   </mvc:interceptor>
</mvc:interceptors>

Using annotations to configure cache interceptors is done following way. In your web config class you can add a bean for WebContentInterceptor class and add it into interceptors list.

@Bean
public WebContentInterceptor webContentInterceptor() {
    WebContentInterceptor interceptor = new WebContentInterceptor();
    interceptor.setCacheSeconds(31556926);
    interceptor.setUseExpiresHeader(true);;
    interceptor.setUseCacheControlHeader(true);
    interceptor.setUseCacheControlNoStore(true);
    return interceptor;
}

@Override
public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(webContentInterceptor());
}

Refer this site to see how it's done.

Upvotes: 8

Related Questions