2010-01-18 114 views
17

CXF文档中提到的缓存为Advanced HTTP如何利用CXF,JAXRS和HTTP缓存

CXF JAXRS通过处理的if-match,如果-Modified-Since的提供了多项先进功能,HTTP支持和ETags标题。 JAXRS请求上下文对象可用于检查前提条件。还支持Vary,CacheControl,Cookies和Set-Cookies。

我真的很喜欢使用(或至少是探索)这些功能。然而,虽然“提供支持”听起来很有趣,但它在实现这些功能方面并不是特别有用。任何关于如何使用If-Modified-Since,CacheControl或ETags的帮助或指针?

回答

27

其实,答案是不特定于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(); 
} 
+4

很好的答案。我唯一的评论是你生成的EntityTag可能不需要该人的UUID。电子标签在相同资源的修订之间更改是非常重要的。假设ID是不可变的,UUID与资源的路径是多余的(尽管你的Impl调用该参数为“name”,所以也许它不是不可变的),并且你应该确保这个值是表示特定的。资源的两种表示方式因媒体类型而异,请使用媒体类型值和版本标识符来创建表示特定的ETag值。 – benvolioT 2011-08-04 20:01:36

+0

我从不使用Response对象 - 只需让CXF处理该部分即可。没有它? – oligofren 2012-06-30 12:12:48

+0

@oligofren我以前从未使用过它们,但那是我找到的唯一解决方案。 – sfussenegger 2012-07-02 15:06:12

5

与即将举行的JAX-RS 2.0将有可能以声明方式应用的Cache-Control,如http://jalg.net/2012/09/declarative-cache-control-with-jax-rs-2-0/解释

您已经可以至少在新泽西州进行测试。虽然不确定CXF和RESTEasy。这里解释

+0

它更像是声明性地应用可以做缓存等过滤器的过滤器,但无论如何,这是一大进步。感谢让我(我们)知道。 – sfussenegger 2012-09-26 09:49:49

0

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

而且如果你用直接返回自己的对象,而不是CXF响应,这是很难添加一个缓存控制头。

我发现通过使用自定义的注释和创建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<String, List<String>> headers = (Map<String, List<String>>) 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

希望这将有助于。

Loïc