web-dev-qa-db-fra.com

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 méthode préférée pour définir les en-têtes de cache pour un chemin spécifique?

58
D. Wroblewski

org.springframework.web.servlet.support.WebContentGenerator , qui est la classe de base de tous les contrôleurs Spring, comporte de nombreuses 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 appelés dans votre contrôleur avant la génération de contenu ou spécifiés en tant que propriétés de bean dans un contexte Spring.

18
ChssPly76

Je viens de rencontrer le même problème et j'ai trouvé une bonne solution déjà fournie par le framework. La classe org.springframework.web.servlet.mvc.WebContentInterceptor vous permet de définir un comportement de mise en cache par défaut, ainsi que des remplacements spécifiques au chemin (avec le même comportement de matrices de chemins que celui utilisé ailleurs). Les étapes pour moi étaient:

  1. Assurez-vous que la propriété "cacheSeconds" n'est pas définie dans mon instance de org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.
  2. Ajoutez 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 modifications, les réponses sous/foo incluaient des en-têtes pour décourager la mise en cache, celles dans/cache/me incluaient des en-têtes pour encourager la mise en cache et les réponses sous/cache/agnostic ne comprenaient aucun en-tête lié au cache.


Si vous utilisez une configuration Java pure:

@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

65
Eric R. Rath

La réponse est assez 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 atteindre. Vous devez faire deux choses. Ajoutez "réponse finale HttpServletResponse" comme paramètre. Et ensuite, définissez l'en-tête Cache-Control sur no-cache. 

28
goroncy

À partir de Spring 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 object est un générateur avec de nombreuses options de configuration, voir JavaDoc

13

Vous pouvez utiliser un intercepteur de gestionnaire et utiliser la méthode postHandle fournie par celui-ci:

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) 

puis ajoutez simplement un en-tête comme suit dans la méthode:

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

vous pouvez définir une annotation pour cela: @CacheControl(isPublic = true, maxAge = 300, sMaxAge = 300), puis la rendre en en-tête HTTP avec l'intercepteur Spring MVC. ou le faire dynamique:

int age = calculateLeftTiming();
String cacheControlValue = CacheControlHeader.newBuilder()
      .setCacheType(CacheType.PUBLIC)
      .setMaxAge(age)
      .setsMaxAge(age).build().stringValue();
if (StringUtils.isNotBlank(cacheControlValue)) {
    response.addHeader("Cache-Control", cacheControlValue);
}

Les implications peuvent être trouvées ici: Bu 的 Builder 模式

BTW: Je viens de constater que Spring MVC dispose d’un support intégré pour le contrôle du cache:.

4
arganzheng

Je sais que c'est très ancien, mais ceux qui googuent pourraient aider:

@Override
protected void addInterceptors(InterceptorRegistry registry) {

    WebContentInterceptor interceptor = new WebContentInterceptor();

    Properties mappings = new Properties();
    mappings.put("/", "2592000");
    mappings.put("/admin", "-1");
    interceptor.setCacheMappings(mappings);

    registry.addInterceptor(interceptor);
}
3
realcnbs

Vous pouvez étendre AnnotationMethodHandlerAdapter pour rechercher une annotation de contrôle de cache personnalisée et définir les en-têtes http en conséquence.

1
user281581

Dans votre contrôleur, vous pouvez définir directement les en-têtes de réponse.

response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
response.setHeader("Pragma", "no-cache");
response.setDateHeader("Expires", 0);
1
hakunami

J'ai trouvé que WebContentInterceptor était le moyen le plus facile d'aller.

@Override
public void addInterceptors(InterceptorRegistry registry)
{
    WebContentInterceptor interceptor = new WebContentInterceptor();
    interceptor.addCacheMapping(CacheControl.noCache(), "/users", "admin");
    registry.addInterceptor(interceptor);
}
0
Liang Zhou