泽西岛:默认缓存控制为无缓存
在编写 RESTful Web 服务时,如果我在客户端(当前是 .NET 厚客户端)上启用任何类型的缓存,则会遇到问题。默认情况下,Jersey 不发送任何类型的缓存控件标头,因此客户端会自动缓存大多数页面(这似乎是有效的行为)。
我希望让泽西岛默认发送“无缓存”的缓存控件,然后特别响应覆盖缓存控件。
有没有办法用泽西岛做到这一点?
我发现RESTeasy能够使用@NoCache注释来指定整个类的设置,但我没有找到与泽西岛类似的东西。
在编写 RESTful Web 服务时,如果我在客户端(当前是 .NET 厚客户端)上启用任何类型的缓存,则会遇到问题。默认情况下,Jersey 不发送任何类型的缓存控件标头,因此客户端会自动缓存大多数页面(这似乎是有效的行为)。
我希望让泽西岛默认发送“无缓存”的缓存控件,然后特别响应覆盖缓存控件。
有没有办法用泽西岛做到这一点?
我发现RESTeasy能够使用@NoCache注释来指定整个类的设置,但我没有找到与泽西岛类似的东西。
使用 ResourceFilterFactory,使用 Jersey 很容易做到这一点 - 您可以创建附加到方法的任何自定义注释来设置缓存控制设置。当应用程序初始化时,资源过滤器会为每个发现的资源方法调用 - 在 ResourceFilterFactory 中,您可以检查该方法是否具有@CacheControlHeader注释(或您想要调用它的任何内容) - 如果没有,只需返回响应过滤器,将“no-cache”指令添加到响应中,否则它应该使用注释中的设置。下面是如何做到这一点的示例:
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;
}
}
}
注释可以如下所示:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface CacheControlHeader {
String value();
}
通过在 Web.xml 中 Jersey servlet 的定义中添加以下 init 参数,可以在您的应用程序中注册 ResourceFilterFactory:
<init-param>
<param-name>com.sun.jersey.spi.container.ResourceFilters</param-name>
<param-value>package.name.CacheFilterFactory</param-value>
</init-param>
基于@martin-matula的解决方案,我创建了两个缓存注释。一个用于根本不缓存,一个用于特定缓存。采用两个参数,因此您不必自己计算秒数:@NoCache
@CacheMaxAge
CacheMaxAge
@GET
@CacheMaxAge(time = 10, unit = TimeUnit.MINUTES)
@Path("/awesome")
public String returnSomethingAwesome() {
...
}
ResourceFilter 现在具有此创建方法,默认情况下不会干扰(因此其他缓存机制继续工作):
@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));
}
您可以在我的博客文章中看到完整的解决方案。
感谢您的解决方案马丁!