Beim Schreiben eines RESTful-Webdiensts stoßen Sie auf Probleme, wenn ich auf meinem Client (derzeit ein .NET Thick Client) eine Art Zwischenspeicherung aktiviere. Standardmäßig sendet Jersey keine Art von Header für die Cache-Steuerung, sodass der Client die meisten Seiten automatisch zwischenspeichert (was ein gültiges Verhalten zu sein scheint).
Ich möchte, dass Jersey standardmäßig eine Cache-Kontrolle von "no-cache" sendet, und dann insbesondere die Antworten die Cache-Kontrolle überschreiben.
Gibt es eine Möglichkeit, dies mit Jersey zu tun?
Ich habe herausgefunden, dass RESTeasy die Möglichkeit hat, die @NoCache-Annotation zu verwenden, um die Einstellung für die gesamte Klasse festzulegen, aber ich habe mit Jersey nichts Ähnliches gefunden.
Mit Jersey ist dies mit Hilfe einer ResourceFilterFactory ganz einfach. Sie können beliebige benutzerdefinierte Anmerkungen erstellen, die Sie mit Ihren Methoden verknüpfen, um Einstellungen für die Cache-Steuerung festzulegen. ResourceFilterFactories wird für jede erkannte Ressourcenmethode aufgerufen, wenn die Anwendung initialisiert wird. In Ihrer ResourceFilterFactory können Sie überprüfen, ob die @CacheControlHeader-Annotation der Methode vorhanden ist (oder wie auch immer Sie sie aufrufen möchten) "Direktive zur Antwort, sonst sollte es die Einstellungen aus der Annotation verwenden. Hier ist ein Beispiel, wie das geht:
public class CacheFilterFactory implements ResourceFilterFactory {
private static final List<ResourceFilter> NO_CACHE_FILTER = Collections.<ResourceFilter>singletonList(new CacheResponseFilter("no-cache"));
@Override
public List<ResourceFilter> create(AbstractMethod am) {
CacheControlHeader cch = am.getAnnotation(CacheControlHeader.class);
if (cch == null) {
return NO_CACHE_FILTER;
} else {
return Collections.<ResourceFilter>singletonList(new CacheResponseFilter(cch.value()));
}
}
private static class CacheResponseFilter implements ResourceFilter, ContainerResponseFilter {
private final String headerValue;
CacheResponseFilter(String headerValue) {
this.headerValue = headerValue;
}
@Override
public ContainerRequestFilter getRequestFilter() {
return null;
}
@Override
public ContainerResponseFilter getResponseFilter() {
return this;
}
@Override
public ContainerResponse filter(ContainerRequest request, ContainerResponse response) {
// attache Cache Control header to each response based on the annotation value
response.getHttpHeaders().putSingle(HttpHeaders.CACHE_CONTROL, headerValue);
return response;
}
}
}
Die Anmerkung kann so aussehen:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface CacheControlHeader {
String value();
}
Die ResourceFilterFactory kann in Ihrer Anwendung registriert werden, indem Sie der Definition des Jersey-Servlets in web.xml den folgenden init-Parameter hinzufügen:
<init-param>
<param-name>com.Sun.jersey.spi.container.ResourceFilters</param-name>
<param-value>package.name.CacheFilterFactory</param-value>
</init-param>
Basierend auf der Lösung von @ martin-matula habe ich zwei Cache-Anmerkungen erstellt. Ein @NoCache
für überhaupt kein Caching und ein @CacheMaxAge
für spezifisches Caching. Die Variable CacheMaxAge
benötigt zwei Argumente, damit Sie die Sekunden nicht selbst berechnen müssen:
@GET
@CacheMaxAge(time = 10, unit = TimeUnit.MINUTES)
@Path("/awesome")
public String returnSomethingAwesome() {
...
}
Der ResourceFilter verfügt jetzt über diese Create-Methode, die standardmäßig nicht interferiert (andere Caching-Mechanismen funktionieren also weiterhin):
@Override
public List<ResourceFilter> create(AbstractMethod am) {
if (am.isAnnotationPresent(CacheMaxAge.class)) {
CacheMaxAge maxAge = am.getAnnotation(CacheMaxAge.class);
return newCacheFilter("max-age: " + maxAge.unit().toSeconds(maxAge.time()));
} else if (am.isAnnotationPresent(NoCache.class)) {
return newCacheFilter("no-cache");
} else {
return Collections.emptyList();
}
}
private List<ResourceFilter> newCacheFilter(String content) {
return Collections
.<ResourceFilter> singletonList(new CacheResponseFilter(content));
}
Sie können die vollständige Lösung in meinem Blogpost sehen.
Danke für die Lösung Martin!
Die Lösung von @ martin-matula funktioniert nicht mit JAX-RS 2.0/Jersey 2.x, da ResourceFilterFactory und ResourceFilter entfernt wurden. Die Lösung kann wie folgt an JAX-RS 2.0 angepasst werden.
Anmerkung:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface CacheControlHeader {
String value();
}
DynamicFeature:
@Provider
public class CacheFilterFactory implements DynamicFeature {
private static final CacheResponseFilter NO_CACHE_FILTER =
new CacheResponseFilter("no-cache");
@Override
public void configure(ResourceInfo resourceInfo,
FeatureContext featureContext) {
CacheControlHeader cch = resourceInfo.getResourceMethod()
.getAnnotation(CacheControlHeader.class);
if (cch == null) {
featureContext.register(NO_CACHE_FILTER);
} else {
featureContext.register(new CacheResponseFilter(cch.value()));
}
}
private static class CacheResponseFilter implements ContainerResponseFilter {
private final String headerValue;
CacheResponseFilter(String headerValue) {
this.headerValue = headerValue;
}
@Override
public void filter(ContainerRequestContext containerRequestContext,
ContainerResponseContext containerResponseContext) {
// attache Cache Control header to each response
// based on the annotation value
containerResponseContext
.getHeaders()
.putSingle(HttpHeaders.CACHE_CONTROL, headerValue);
}
}
}
CacheFilterFactory muss bei Jersey registriert sein. Ich mache das über Dropwizard - mithilfe von environment.jersey (). Register () -, aber ich verstehe, dass dies auf Standalone-Systemen der Fall ist, indem Sie Jersey Ihre Klassen nach @Provider-Anmerkungen scannen lassen, indem Sie Folgendes in Ihrer web.xml definieren :
<servlet>
<servlet-name>my.package.MyApplication</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<!-- Register resources and providers under my.package. -->
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>my.package</param-value>
</init-param>
</servlet>
In diesem Beitrag finden Sie weitere Informationen zum Registrieren von Komponenten.
Ich denke, du kannst das benutzen
isNoCache(true)
das wird das Cachen im Browser beenden.
Sehen:
http://jersey.Java.net/nonav/apidocs/1.12/jersey/javax/ws/rs/core/CacheControl.html#isNoCache%28%29
Hoffe das hilft.
Ich habe eine Anmerkung gefunden, die das Zwischenspeichern deaktivieren kann. Sie können die folgenden Anmerkungen für Ihre API verwenden:
@CacheControl(noCache = true)