4

I am using spring-boot and want to prevent caching of index.html but cache all other resources, I have put the resource files on my classpath and prevented caching using the following.

Currently I am doing the following which is caching all files.

@Configuration
public class StaticResourceConfig extends WebMvcConfigurerAdapter {

    private static final int SEVEN_DAYS_IN_SECONDS = 604800;

    @Override
    public void addResourceHandlers(final ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/**")
                .addResourceLocations("classpath:frontend/dist/")
                .setCachePeriod(SEVEN_DAYS_IN_SECONDS);
        super.addResourceHandlers(registry);
    }

}

The index.html file is located at frontend/dist/index.html

4 Answers 4

3

I managed to do it this way:

@Override
public void addResourceHandlers(final ResourceHandlerRegistry registry) {

   registry.addResourceHandler("/index.html")
            .addResourceLocations("classpath:frontend/dist/index.html")
            .setCachePeriod(0);

   registry.addResourceHandler("/assets/**")
            .addResourceLocations("classpath:frontend/dist/assets")
            .setCachePeriod(SEVEN_DAYS_IN_SECONDS);

    super.addResourceHandlers(registry);
}
Sign up to request clarification or add additional context in comments.

1 Comment

You can use CacheControl.maxAge() rather than creating constants manually.
2

Using spring boot 2.1.1 and additionally spring security 5.1.1.

1. For resources using resourcehandler in code (UNTESTED):

You can add customized extensions of resources this way.

registry.addResourceHandler

Is for adding the uri path where to get the resource/s

.addResourceLocations

Is for setting the location in the filesystem where the resources are located( given is a relative with classpath

.setCacheControl
.setCachePeriod

Is for setting the cache headers (self explanatory.)

Resourcechain and resolver are optional (in this case exactly as the default values.)

@Configuration
public class CustomWebMVCConfig implements WebMvcConfigurer {

private static final int SEVEN_DAYS_IN_SECONDS = 604800;

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) 
    registry.setOrder(1).addResourceHandler("/index.html")
            .addResourceLocations("classpath:frontend/dist/")
            .setCacheControl(CacheControl.maxAge(0, TimeUnit.SECONDS)
                    .mustRevalidate())
            .setCacheControl(CacheControl.noCache())
            .setCacheControl(CacheControl.noStore())
            .resourceChain(true)
            .addResolver(new PathResourceResolver());

    registry.setOrder(0).addResourceHandler("/**")
            .addResourceLocations("classpath:frontend/dist/")
            .setCachePeriod(SEVEN_DAYS_IN_SECONDS)
            .resourceChain(true)
            .addResolver(new PathResourceResolver());
}

2. At controller level

(yourwebsite.com/index.html)

@GetMapping("/index.html")
public void getIndex(HttpServletResponse response) {
    response.setHeader(HttpHeaders.CACHE_CONTROL,
             "no-cache, no-store, max-age=0, must-revalidate");
}

Comments

0

You can use MappedInterceptor and WebContentInterceptor as more flexible solution of configuring Cache-Control headers to different static resources.

    @Bean
    public MappedInterceptor cacheControlInterceptor() {
        WebContentInterceptor webContentInterceptor = new WebContentInterceptor();
        webContentInterceptor.setCacheControl(CacheControl.maxAge(0, TimeUnit.SECONDS).cachePublic());
        webContentInterceptor.addCacheMapping(CacheControl.noStore().mustRevalidate(), "/index.html");
        // if using Spring Security CacheControlHeadersWriter:
        // webContentInterceptor.addCacheMapping(CacheControl.empty(), "/", "/index.html");
        return new MappedInterceptor(null, webContentInterceptor);
    }

Why is bean needed? Please see Note

See also: SPR-10655 and SPR-13780 (it can be strange because even Spring Security CacheControlHeadersWriter use chain of 4 directives such as "no-cache, no-store, max-age=0, must-revalidate")

1 Comment

This does not work for me as the ResourceHttpRequestHandler is overwriting the Cache Headers written by cacheControllInterceptor
0

Solution by jax is fine but be aware not to extend WebMvcConfigurationSupport otherwise it does not work and with spring boot you can extend the config and so you don't need the second part. This piece of code works:

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
 
@Configuration
public class SinglePageApplicationResourceHandler implements WebMvcConfigurer {

    @Override
    public void addResourceHandlers(final ResourceHandlerRegistry registry) {

        registry.addResourceHandler("/index.html")
                .addResourceLocations("classpath:/public/index.html")
                .setCachePeriod(0);
    }
}

And you usually need to extend it with a catch all mapping like this:

@Controller
public class SinglePageApplicationController {

  @RequestMapping("/**/{path:[^.]*}")
  public String redirect() {
    return "forward:/index.html";
  }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.