web-dev-qa-db-fra.com

Comment activer la mise en cache de réponse HTTP dans Spring Boot

J'ai implémenté un serveur REST à l'aide de Spring Boot 1.0.2. Je ne parviens pas à empêcher Spring de définir des en-têtes HTTP qui désactivent la mise en cache HTTP.

Mon contrôleur est comme suit:

@Controller
public class MyRestController {
    @RequestMapping(value = "/someUrl", method = RequestMethod.GET)
    public @ResponseBody ResponseEntity<String> myMethod(
            HttpServletResponse httpResponse) throws SQLException {
        return new ResponseEntity<String>("{}", HttpStatus.OK);
    }
}

Toutes les réponses HTTP contiennent les en-têtes suivants:

Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Expires: 0
Pragma: no-cache

J'ai essayé ce qui suit pour supprimer ou modifier ces en-têtes:

  1. Appelez setCacheSeconds(-1) dans le contrôleur.
  2. Appelez httpResponse.setHeader("Cache-Control", "max-age=123") dans le contrôleur.
  3. Définissez @Bean qui retourne WebContentInterceptor pour lequel j'ai appelé setCacheSeconds(-1).
  4. Définissez la propriété spring.resources.cache-period sur -1 ou une valeur positive dans application.properties.

Aucune de ces réponses n'a eu d'effet. Comment désactiver ou modifier ces en-têtes pour toutes les requêtes ou des requêtes individuelles dans Spring Boot?

39

Il s'avère que les en-têtes HTTP sans cache sont définis par Spring Security. Ceci est discuté dans http://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#headers .

Ce qui suit désactive l'en-tête de réponse HTTP Pragma: no-cache, mais ne résout pas le problème autrement:

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

J'ai fini par désactiver complètement Spring Security pour les ressources statiques publiques comme suit (dans la même classe que ci-dessus):

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

Cela nécessite la configuration de deux gestionnaires de ressources pour obtenir des en-têtes de contrôle de cache corrects:

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

Voir aussi Utilisation de ressources Web statiques dans l'application Spring Boot & Spring Security .

48

J'ai trouvé cette extension Spring: https://github.com/foo4u/spring-mvc-cache-control .

Vous devez juste faire trois étapes.

Étape 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>

Étape 2 (WebMvcConfiguration.Java):

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

Étape 3 (contrôleur):

@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);
    }
}
4
dap.tci

Pour le démarrage printanier, il y a beaucoup de façons de mettre en cache http. Utilisation de la botte à ressort 2.1.1 et de la sécurité à ressort 5.1.1.

1. Pour les ressources utilisant resourcehandler dans le code:

Vous pouvez ajouter des extensions de ressources personnalisées de cette façon.

registry.addResourceHandler

Est pour ajouter le chemin URI où obtenir la ressource

.addResourceLocations

Permet de définir l'emplacement dans le système de fichiers où se trouvent les ressources ( Est donné avec un chemin classpath mais le chemin absolu avec file :: // est également possible.)

.setCacheControl

Permet de définir les en-têtes de cache (explicite.)

Resourcechain et resolver sont facultatifs (dans ce cas, exactement comme les valeurs par défaut).

@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. Pour les ressources utilisant le fichier de configuration des propriétés d'application

Comme ci-dessus, moins les modèles spécifiques, mais maintenant sous la forme config . Cette configuration est appliquée à toutes les ressources des emplacements statiques répertoriés.

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. Au niveau du contrôleur

La réponse ici est HttpServletResponse injectée dans la méthode du contrôleur en tant que paramètre.

no-cache, must-revalidate, private

getHeaderValue affichera les options du cache sous forme de chaîne. par exemple. 

response.setHeader(HttpHeaders.CACHE_CONTROL,
            CacheControl.noCache()
                    .cachePrivate()
                    .mustRevalidate()
                    .getHeaderValue());
1
Merv

Si vous ne souhaitez pas authentifier vos ressources statiques, vous pouvez procéder comme suit:

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

et dans votre application.properties:

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

Voir ResourceProperties.Java pour plus de propriétés pouvant être définies.

0
cstroe
@Configuration
@EnableAutoConfiguration
public class WebMvcConfiguration extends WebMvcConfigurerAdapter {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {

        registry.addResourceHandler("/resources/**")
                .addResourceLocations("/resources/")
                .setCachePeriod(31556926);

    }
}
0
Vazgen Torosyan

Je rencontre un problème similaire. Je voulais obtenir quelques-unes des ressources dynamiques (images) mises en cache dans le navigateur. Si l'image change (pas très souvent) je change la partie d'uri ... C'est ma solution

    http.headers().cacheControl().disable();
    http.headers().addHeaderWriter(new HeaderWriter() {

        CacheControlHeadersWriter originalWriter = new CacheControlHeadersWriter();

        @Override
        public void writeHeaders(HttpServletRequest request, HttpServletResponse response) {
            Collection<String> headerNames = response.getHeaderNames();
            String requestUri = request.getRequestURI();
            if(!requestUri.startsWith("/web/eventImage")) {
                originalWriter.writeHeaders(request, response);
            } else {
               //write header here or do nothing if it was set in the code
            }       
        }
    });
0
Michal Ambrož