How to enable HTTP response caching in Spring Boot

前端 未结 8 1794
我寻月下人不归
我寻月下人不归 2020-11-27 12:17

I have implemented a REST server using Spring Boot 1.0.2. I\'m having trouble preventing Spring from setting HTTP headers that disable HTTP caching.

My controller is

相关标签:
8条回答
  • 2020-11-27 12:58

    Turns out the no-cache HTTP headers are set by Spring Security. This is discussed in http://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#headers.

    The following disables the HTTP response header Pragma: no-cache, but doesn't otherwise solve the problem:

    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;
    
    @Configuration
    @EnableWebMvcSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            // Prevent the HTTP response header of "Pragma: no-cache".
            http.headers().cacheControl().disable();
        }
    }
    

    I ended up disabling Spring Security completely for public static resources as following (in the same class as above):

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/static/public/**");
    }
    

    This requires configuring two resource handlers to get cache control headers right:

    @Configuration
    public class MvcConfigurer extends WebMvcConfigurerAdapter
            implements EmbeddedServletContainerCustomizer {
        @Override
        public void addResourceHandlers(ResourceHandlerRegistry registry) {
            // Resources without Spring Security. No cache control response headers.
            registry.addResourceHandler("/static/public/**")
                .addResourceLocations("classpath:/static/public/");
    
            // Resources controlled by Spring Security, which
            // adds "Cache-Control: must-revalidate".
            registry.addResourceHandler("/static/**")
                .addResourceLocations("classpath:/static/")
                .setCachePeriod(3600*24);
        }
    }
    

    See also Serving static web resources in Spring Boot & Spring Security application.

    0 讨论(0)
  • 2020-11-27 12:59

    There are a lot of ways in spring boot for http caching. Using spring boot 2.1.1 and additionally spring security 5.1.1.

    1. For resources using resourcehandler in code:

    You can add customized extensions of resources this way.

    registry.addResourceHandler
    

    Is for adding the uri path where to get the resource

    .addResourceLocations
    

    Is for setting the location in the filesystem where the resources are located( given is a relative with classpath but absolute path with file::// is also possible.)

    .setCacheControl
    

    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 {
    
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/*.js", "/*.css", "/*.ttf", "/*.woff", "/*.woff2", "/*.eot",
                "/*.svg")
                .addResourceLocations("classpath:/static/")
                .setCacheControl(CacheControl.maxAge(365, TimeUnit.DAYS)
                        .cachePrivate()
                        .mustRevalidate())
                .resourceChain(true)
                .addResolver(new PathResourceResolver());
        }
    }
    

    2. For resources using application properties config file

    Same as above, minus the specific patterns, but now as config. This configuration is applied to all resources in the static-locations listed.

    spring.resources.cache.cachecontrol.cache-private=true
    spring.resources.cache.cachecontrol.must-revalidate=true
    spring.resources.cache.cachecontrol.max-age=31536000
    spring.resources.static-locations=classpath:/static/
    

    3. At controller level

    Response here is the HttpServletResponse injected in the controller method as parameter.

    no-cache, must-revalidate, private
    

    getHeaderValue will output the cache options as string. e.g.

    response.setHeader(HttpHeaders.CACHE_CONTROL,
                CacheControl.noCache()
                        .cachePrivate()
                        .mustRevalidate()
                        .getHeaderValue());
    
    0 讨论(0)
  • 2020-11-27 13:03

    Overriding of default caching behavior for a particular method can be done in the below way:

    @Controller
    public class MyRestController {
        @RequestMapping(value = "/someUrl", method = RequestMethod.GET)
        public @ResponseBody ResponseEntity<String> myMethod(
                HttpServletResponse httpResponse) throws SQLException {
            return new ResponseEntity.ok().cacheControl(CacheControl.maxAge(100, TimeUnit.SECONDS)).body(T)
        }
    }
    
    0 讨论(0)
  • 2020-11-27 13:11

    I have found this Spring extension: https://github.com/foo4u/spring-mvc-cache-control.

    You just have to do three steps.

    Step 1 (pom.xml):

    <dependency>
        <groupId>net.rossillo.mvc.cache</groupId>
        <artifactId>spring-mvc-cache-control</artifactId>
        <version>1.1.1-RELEASE</version>
        <scope>compile</scope>
    </dependency>
    

    Step 2 (WebMvcConfiguration.java):

    @Configuration
    public class WebMvcConfig extends WebMvcConfigurerAdapter implements WebMvcConfigurer {
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(new CacheControlHandlerInterceptor());
        }
    }
    

    Step 3 (Controller):

    @Controller
    public class MyRestController {
    
        @CacheControl(maxAge=31556926)
        @RequestMapping(value = "/someUrl", method = RequestMethod.GET)
        public @ResponseBody ResponseEntity<String> myMethod(
                HttpServletResponse httpResponse) throws SQLException {
            return new ResponseEntity<String>("{}", HttpStatus.OK);
        }
    }
    
    0 讨论(0)
  • 2020-11-27 13:11

    If you don't care to have your static resources authenticated, you could do this:

    import static org.springframework.boot.autoconfigure.security.servlet.PathRequest.toStaticResources;
    
    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    ...
        @Override
        public void configure(WebSecurity webSecurity) throws Exception {
            webSecurity
                    .ignoring()
                    .requestMatchers(toStaticResources().atCommonLocations());
        }
    ...
    }
    

    and in your application.properties:

    spring.resources.cache.cachecontrol.max-age=43200
    

    See ResourceProperties.java for more properties that can be set.

    0 讨论(0)
  • 2020-11-27 13:16
    @Configuration
    @EnableAutoConfiguration
    public class WebMvcConfiguration extends WebMvcConfigurerAdapter {
    
        @Override
        public void addResourceHandlers(ResourceHandlerRegistry registry) {
    
            registry.addResourceHandler("/resources/**")
                    .addResourceLocations("/resources/")
                    .setCachePeriod(31556926);
    
        }
    }
    
    0 讨论(0)
提交回复
热议问题