Welche bevorzugte Methode zum Festlegen von Cache-Headern für einen bestimmten Pfad in einem auf Anmerkungen basierenden Spring MVC-Controller?
org.springframework.web.servlet.support.WebContentGenerator , der Basisklasse für alle Spring-Controller, verfügt über einige Methoden, die Cache-Header behandeln:
/* 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);
Sie können entweder vor der Inhaltsgenerierung in Ihrem Controller aufgerufen oder als Bean-Eigenschaften im Spring-Kontext angegeben werden.
Ich bin gerade auf das gleiche Problem gestoßen und habe eine gute Lösung gefunden, die das Framework bereits bietet. Mit der Klasse org.springframework.web.servlet.mvc.WebContentInterceptor
können Sie das standardmäßige Caching-Verhalten sowie pfadspezifische Überschreibungen festlegen (mit demselben Pfad-Matcher-Verhalten, das an anderer Stelle verwendet wird). Die Schritte für mich waren:
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter
nicht die Eigenschaft "cacheSeconds" festgelegt ist.Fügen Sie eine Instanz von WebContentInterceptor
hinzu:
<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>
Nach diesen Änderungen enthielten die Antworten unter/foo Header zum Verhindern des Caching, die Antworten unter/cache/me die Header, um das Caching zu fördern, und die Antworten unter/cache/agnostic enthielten keine Cache-bezogenen Header.
Wenn Sie eine reine Java-Konfiguration verwenden:
@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);
}
}
Siehe auch: http://docs.spring.io/spring-security/site/docs/current/reference/html/headers.html
Die Antwort ist ganz einfach:
@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);
}
}
Der Code oben zeigt genau, was Sie erreichen möchten. Sie müssen zwei Dinge tun. Fügen Sie als Parameter "endgültige HttpServletResponse-Antwort" hinzu. Und dann setzen Sie Header Cache-Control auf No-Cache. Mit Spring 4.2 können Sie Folgendes tun:
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 ist ein Builder mit vielen Konfigurationsoptionen, siehe JavaDoc
Sie können einen Handler-Interceptor verwenden und die von ihm bereitgestellte postHandle-Methode verwenden:
postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
dann fügen Sie einfach einen Header in der Methode hinzu:
response.setHeader("Cache-Control", "no-cache");
sie können dazu eine Anmerkung definieren: @CacheControl(isPublic = true, maxAge = 300, sMaxAge = 300)
. Diese Anmerkung wird dann mit Spring MVC-Interceptor im HTTP-Header dargestellt. oder mach es dynamisch:
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);
}
Implikationen finden Sie hier: Build 的 Builder 模式
BTW: Ich habe gerade herausgefunden, dass Spring MVC eine integrierte Unterstützung für die Cache-Steuerung bietet: Google WebContentInterceptor oder CacheControlHandlerInterceptor oder CacheControl.
Ich weiß, das ist wirklich alt, aber die, die googeln, könnten helfen:
@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);
}
Sie können AnnotationMethodHandlerAdapter erweitern, um nach einer benutzerdefinierten Cache-Steuerelementanmerkung zu suchen und die http-Header entsprechend festzulegen.
In Ihrem Controller können Sie Antwortheader direkt festlegen.
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
response.setHeader("Pragma", "no-cache");
response.setDateHeader("Expires", 0);
Ich fand, dass WebContentInterceptor
der einfachste Weg ist.
@Override
public void addInterceptors(InterceptorRegistry registry)
{
WebContentInterceptor interceptor = new WebContentInterceptor();
interceptor.addCacheMapping(CacheControl.noCache(), "/users", "admin");
registry.addInterceptor(interceptor);
}