65 votes

Comment définir les en-têtes de cache dans Spring MVC ?

Dans un contrôleur Spring MVC basé sur des annotations, quelle est la meilleure façon de définir les en-têtes de cache pour un chemin spécifique ?

0 votes

Pour les nouveaux utilisateurs, c'est probablement la réponse que vous cherchez

67voto

Eric R. Rath Points 1062

Je viens de rencontrer le même problème, et j'ai trouvé une bonne solution déjà fournie par le framework. Le site org.springframework.web.servlet.mvc.WebContentInterceptor vous permet de définir un comportement de mise en cache par défaut, plus des surcharges spécifiques au chemin (avec le même comportement de path-matcher utilisé ailleurs). Les étapes pour moi ont été les suivantes :

  1. Assurez-vous que mon instance de org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter n'a pas la propriété "cacheSeconds" définie.
  2. Ajouter une instance de WebContentInterceptor :

    <mvc:interceptors>
    ...
    <bean class="org.springframework.web.servlet.mvc.WebContentInterceptor" p:cacheSeconds="0" p:alwaysUseFullPath="true" >
        <property name="cacheMappings">
            <props>
                <!-- cache for one month -->
                <prop key="/cache/me/**">2592000</prop>
                <!-- don't set cache headers -->
                <prop key="/cache/agnostic/**">-1</prop>
            </props>
        </property>
    </bean>
    ...
    </mvc:interceptors>

Après ces changements, les réponses sous /foo incluaient des en-têtes pour décourager la mise en cache, les réponses sous /cache/me incluaient des en-têtes pour encourager la mise en cache, et les réponses sous /cache/agnostic n'incluaient aucun en-tête lié à la mise en cache.


Si vous utilisez une configuration purement Java :

@EnableWebMvc
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
  /* Time, in seconds, to have the browser cache static resources (one week). */
  private static final int BROWSER_CACHE_CONTROL = 604800;

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

Voir aussi : http://docs.spring.io/spring-security/site/docs/current/reference/html/headers.html

0 votes

J'ai essayé de l'utiliser pour les images stockées dans la base de données. Je peux facilement les récupérer. Elles s'affichent, mais FireBug me renvoie toujours le statut "200 Ok", donc pas de mise en cache. Avez-vous une idée ?

1 votes

Cela ne fonctionnera pas parce que je n'ai pas de préfixe de mvc, ou de p. Que sont-ils censés être ?

0 votes

Jesse - vérifiez l'élément Root de votre fichier context def ; vous devriez avoir un élément namespace comme 'xmlns:mvc=" springframework.org/schema/mvc "", et un autre attribut nommé "xsi:schemaLocation" dont la valeur comprend ' springframework.org/schema/mvc springframework.org/schema/mvc/spring-mvc-3.1.xsd '. Voir static.springsource.org/spring/docs/3.1.x/ pour un exemple de configuration XML typique.

33voto

goroncy Points 344

La réponse est très simple :

@Controller
public class EmployeeController {
    @RequestMapping(value = "/find/employer/{employerId}", method = RequestMethod.GET)
    public List getEmployees(@PathVariable("employerId") Long employerId, final HttpServletResponse response) {
        response.setHeader("Cache-Control", "no-cache");
        return employeeService.findEmployeesForEmployer(employerId);
    }
}

Le code ci-dessus montre exactement ce que vous voulez obtenir. Vous devez faire deux choses. Ajouter "final HttpServletResponse response" comme paramètre. Et ensuite mettre le header Cache-Control à no-cache.

10 votes

Il faudrait l'ajouter à chaque demande. Ce n'est pas une bonne solution pour ajouter l'en-tête à toutes les demandes.

0 votes

@JesseJ Quelle partie n'a pas fonctionné ? J'ai essayé et ça marche pour moi.

0 votes

@yincrash, je cite l'OP : quelle est la meilleure façon de définir les en-têtes de cache pour une voie spécifique

20voto

ChssPly76 Points 53452

org.springframework.web.servlet.support.WebContentGenerator qui est la classe de base de tous les contrôleurs de Spring, comporte un certain nombre de méthodes traitant des en-têtes de cache :

/* Set whether to use the HTTP 1.1 cache-control header. Default is "true".
 * <p>Note: Cache headers will only get applied if caching is enabled
 * (or explicitly prevented) for the current request. */
public final void setUseCacheControlHeader();

/* Return whether the HTTP 1.1 cache-control header is used. */
public final boolean isUseCacheControlHeader();

/* Set whether to use the HTTP 1.1 cache-control header value "no-store"
 * when preventing caching. Default is "true". */
public final void setUseCacheControlNoStore(boolean useCacheControlNoStore);

/* Cache content for the given number of seconds. Default is -1,
 * indicating no generation of cache-related headers.
 * Only if this is set to 0 (no cache) or a positive value (cache for
 * this many seconds) will this class generate cache headers.
 * The headers can be overwritten by subclasses, before content is generated. */
public final void setCacheSeconds(int seconds);

Ils peuvent être invoqués dans votre contrôleur avant la génération du contenu ou spécifiés comme propriétés du bean dans le contexte de Spring.

3 votes

Mais, comme je l'ai écrit dans ma question, j'utilise un contrôleur basé sur des annotations qui ne sous-classe aucune classe de base de Spring. En quoi cela peut-il m'aider ?

4 votes

Si vous souhaitez modifier les paramètres du cache en fonction de voie spécifique en prolongeant AbstractController est de loin la solution la plus simple. Si vous souhaitez appliquer vos paramètres de cache à tous les contrôleurs, vous pouvez les spécifier dans la section AnnotationMethodHandlerAdapter dans le contexte de Spring pour les contrôleurs basés sur des annotations. Voici un exemple : static.springsource.org/spring/docs/2.5.6/reference/ (ne tenez pas compte du classeur init, vous n'en avez pas besoin)

6 votes

Parce que ma question portait sur la façon de faire cela avec un contrôleur basé sur les annotations. Votre solution ne s'applique qu'aux contrôleurs qui sous-classent WebContentGenerator. N'est-ce pas ?

18voto

En commençant par Printemps 4.2 vous pouvez le faire :

import org.springframework.http.CacheControl;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.TimeUnit;

@RestController
public class CachingController {
    @RequestMapping(method = RequestMethod.GET, path = "/cachedapi")
    public ResponseEntity<MyDto> getPermissions() {

        MyDto body = new MyDto();

        return ResponseEntity.ok()
            .cacheControl(CacheControl.maxAge(20, TimeUnit.SECONDS))
            .body(body);
    }
}

CacheControl est un constructeur avec de nombreuses options de configuration, voir JavaDoc

11voto

Jon Points 23749

Vous pouvez utiliser un intercepteur Handler et utiliser la méthode postHandle qu'il fournit :

http://static.springsource.org/spring/docs/2.0.x/api/org/springframework/web/servlet/HandlerInterceptor.html

postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) 

il suffit alors d'ajouter un en-tête comme suit dans la méthode :

response.setHeader("Cache-Control", "no-cache");

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X