2010-01-18 26 views
17

Các tài liệu CXF đề cập đến bộ nhớ đệm như Advanced HTTP:Làm thế nào để sử dụng CXF, JAXRS và HTTP Caching

CXF JAXRS cung cấp hỗ trợ cho một số tính năng tiên tiến HTTP bằng cách xử lý If-Match, If-Modified-Since và các tiêu đề ETags. JAXRS Yêu cầu đối tượng bối cảnh có thể được sử dụng để kiểm tra các điều kiện tiên quyết. Vary, CacheControl, Cookies và Set-Cookies cũng được hỗ trợ.

Tôi thực sự quan tâm đến việc sử dụng (hoặc ít nhất là khám phá) các tính năng này. Tuy nhiên, trong khi "cung cấp hỗ trợ" âm thanh thực sự thú vị, nó không phải là đặc biệt hữu ích trong việc thực hiện các tính năng như vậy. Bất kỳ trợ giúp hoặc gợi ý về cách sử dụng If-Modified-Since, CacheControl hoặc ETags?

Trả lời

27

Trên thực tế, câu trả lời là không cụ thể cho CXF - đó là tinh khiết 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

Câu trả lời hay. Nhận xét duy nhất của tôi là EntityTag bạn tạo ra có lẽ không cần UUID của người đó. Điều quan trọng là thay đổi eTag giữa các phiên bản của cùng một tài nguyên. Giả sử ID là không thay đổi, UUID là dự phòng với đường dẫn đến tài nguyên (mặc dù Impl của bạn gọi tham số đó là "name", vì vậy có lẽ nó không phải là bất biến. Ngoài ra, bạn nên đảm bảo rằng giá trị này là đại diện cụ thể. Ví dụ, nếu hai biểu diễn của một tài nguyên thay đổi theo loại phương tiện truyền thông, sử dụng giá trị loại phương tiện truyền thông cùng với định danh phiên bản để tạo ra một giá trị ETAG đại diện cụ thể – benvolioT

+0

Tôi không bao giờ sử dụng một đối tượng Response - chỉ cần để CXF xử lý phần đó. không có nó? – oligofren

+0

@oligofren Tôi chưa bao giờ sử dụng chúng bản thân mình trước đây nhưng đó là giải pháp duy nhất tôi tìm thấy – sfussenegger

5

Với sự sắp tới JAX-RS 2.0 nó sẽ có thể áp dụng Cache-Control khai báo, như được giải thích trong http://jalg.net/2012/09/declarative-cache-control-with-jax-rs-2-0/

Bạn đã có thể thử nghiệm điều này ít nhất với Jersey. Bạn không chắc chắn về CXF và RESTEasy.

+0

Nó giống như tuyên bố áp dụng các bộ lọc có thể làm những việc như bộ nhớ đệm, nhưng dù sao thì cải thiện lớn. Cảm ơn vì đã cho tôi (chúng tôi) biết. – sfussenegger

0

CXF không thực hiện lọc động như đã giải thích ở đây: http://www.jalg.net/2012/09/declarative-cache-control-with-jax-rs-2-0

Và nếu bạn sử dụng để quay trở lại trực tiếp đối tượng của riêng bạn và không CXF đáp ứng, thật khó để thêm một tiêu đề kiểm soát bộ nhớ cache.

Tôi tìm một cách thanh lịch bằng cách sử dụng chú thích tùy chỉnh và tạo Bộ chặn đánh dấu CXF đọc chú thích này và thêm tiêu đề.

Vì vậy, đầu tiên, tạo ra một chú thích CacheControl

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

Sau đó, thêm chú thích này để CXF phương pháp hoạt động của bạn (giao diện hoặc thực hiện nó hoạt động trên cả hai nếu bạn sử dụng một giao diện)

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

Sau đó, tạo ra một bộ chặn đánh chặn CacheControl sẽ xử lý chú thích và thêm tiêu đề vào phản hồi của bạn.

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())); 
    } 
} 

Cuối cùng cấu hình CXF sử dụng đánh chặn, bạn có thể tìm thấy tất cả các thông tin cần thiết ở đây: http://cxf.apache.org/docs/interceptors.html

Hy vọng nó sẽ giúp.

Loïc

Các vấn đề liên quan