Как использовать CXF, JAX-RS и HTTP-кеширование - PullRequest
17 голосов
/ 18 января 2010

Документация CXF упоминает кэширование как Расширенный HTTP :

CXF JAXRS обеспечивает поддержку ряда расширенных функций HTTP, обрабатывая заголовки If-Match, If-Modified-Since и ETags. Объект контекста JAXRS-запроса можно использовать для проверки предварительных условий. Также поддерживаются Vary, CacheControl, Cookies и Set-Cookies.

Мне действительно интересно использовать (или хотя бы изучить) эти функции. Однако, хотя «обеспечивает поддержку» звучит очень интересно, это не особенно полезно при реализации таких функций. Любая помощь или указатели о том, как использовать If-Modified-Since, CacheControl или ETags?

Ответы [ 3 ]

27 голосов
/ 19 января 2010

На самом деле, ответ не является специфическим для 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();
}
5 голосов
/ 25 сентября 2012

С выходом JAX-RS 2.0 станет возможным декларативное применение Cache-Control, как объяснено в http://jalg.net/2012/09/declarative-cache-control-with-jax-rs-2-0/

Вы уже можете проверить это, по крайней мере, с Джерси. Не уверен насчет CXF и RESTEasy.

0 голосов
/ 08 февраля 2018

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<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

Надеюсь, это поможет.

Лоик

...