如何使用CXF,JAX-RS和HTTP缓存

CXF文档提到缓存为高级HTTP :

CXF JAXRS通过处理If-Match,If-Modified-Since和ETags标头提供对许多高级HTTPfunction的支持。 JAXRS Request上下文对象可用于检查前提条件。 还支持Vary,CacheControl,Cookies和Set-Cookies。

我真的很想使用(或至少探索)这些function。 然而,虽然“提供支持”的声音非常有趣,但它在实现这些function方面并不是特别有用。 有关如何使用If-Modified-Since,CacheControl或ETags的任何帮助或指示?

实际上,答案并非特定于CXF – 它是纯粹的JAX-RS:

// IPersonService.java import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.core.Context; import javax.ws.rs.core.Request; import javax.ws.rs.core.Response; @GET @Path("/person/{id}") Response getPerson(@PathParam("id") String id, @Context Request request); // PersonServiceImpl.java import javax.ws.rs.core.CacheControl; import javax.ws.rs.core.EntityTag; import javax.ws.rs.core.Request; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.ResponseBuilder; public Response getPerson(String name, Request request) { Person person = _dao.getPerson(name); if (person == null) { return Response.noContent().build(); } EntityTag eTag = new EntityTag(person.getUUID() + "-" + person.getVersion()); CacheControl cc = new CacheControl(); cc.setMaxAge(600); ResponseBuilder builder = request.evaluatePreconditions(person.getUpdated(), eTag); if (builder == null) { builder = Response.ok(person); } return builder.cacheControl(cc).lastModified(person.getUpdated()).build(); } 

使用即将推出的JAX-RS 2.0,可以声明性地应用Cache-Control,如http://jalg.net/2012/09/declarative-cache-control-with-jax-rs-2-0/中所述。

你已经可以测试至少使用泽西岛了。 虽然不确定CXF和RESTEasy。

CXF没有实现动态过滤,如下所述: http : //www.jalg.net/2012/09/declarative-cache-control-with-jax-rs-2-0

如果您使用直接返回自己的对象而不是CXF Response,则很难添加缓存控件头。

我通过使用自定义注释并创建一个读取此注释并添加标题的CXF拦截器来找到一种优雅的方法。

首先,创建一个CacheControl注释

 @Target(ElementType.METHOD ) @Retention(RetentionPolicy.RUNTIME) public @interface CacheControl { String value() default "no-cache"; } 

然后,将此注释添加到您的CXF操作方法(如果您使用接口,它可以在两者上工作的接口或实现)

 @CacheControl("max-age=600") public Person getPerson(String name) { return personService.getPerson(name); } 

然后创建一个CacheControl拦截器,它将处理注释并将标头添加到您的响应中。

 public class CacheInterceptor extends AbstractOutDatabindingInterceptor{ public CacheInterceptor() { super(Phase.MARSHAL); } @Override public void handleMessage(Message outMessage) throws Fault { //search for a CacheControl annotation on the operation OperationResourceInfo resourceInfo = outMessage.getExchange().get(OperationResourceInfo.class); CacheControl cacheControl = null; for (Annotation annot : resourceInfo.getOutAnnotations()) { if(annot instanceof CacheControl) { cacheControl = (CacheControl) annot; break; } } //fast path for no cache control if(cacheControl == null) { return; } //search for existing headers or create new ones Map> headers = (Map>) outMessage.get(Message.PROTOCOL_HEADERS); if (headers == null) { headers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); outMessage.put(Message.PROTOCOL_HEADERS, headers); } //add Cache-Control header headers.put("Cache-Control", Collections.singletonList(cacheControl.value())); } } 

最后配置CXF使用你的拦截器,你可以在这里找到所有需要的信息: http : //cxf.apache.org/docs/interceptors.html

希望它会有所帮助。

卢瓦克