Pregunta

CXF menciona como el almacenamiento en caché Avanzado HTTP :

  

CXF JAXRS proporciona soporte para una serie de características avanzadas por el manejo de HTTP If-Match, If-Modified-Since y las cabeceras eTags. JAXRS objeto Request contexto puede ser utilizado para verificar las condiciones previas. Vary, CacheControl, también se apoyan las galletas y Set-cookies.

Estoy muy interesado en el uso (o al menos la exploración de) estas características. Sin embargo, mientras que "brinda apoyo" suena muy interesante, no es particularmente útil en la aplicación de tales características. Cualquier ayuda o consejos sobre cómo utilizar If-Modified-Since, CacheControl o ETags?

¿Fue útil?

Solución

En realidad, la respuesta no es específico de CXF - Es pura 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();
}

Otros consejos

Con la próxima JAX-RS 2.0 será posible aplicar Cache-Control declarativa, como se explica en http://jalg.net/2012/09/declarative-cache-control-with-jax-rs-2-0/

Ya se puede probar esto por lo menos con Jersey. No estoy seguro sobre CXF y RESTEasy sin embargo.

CXF no se implementa el filtrado dinámico como se explica aquí: http://www.jalg.net/2012/09/declarative-cache-control-with-jax-rs-2-0

Y si se utiliza para volver directamente a sus propios objetos y la respuesta no CXF, es difícil añadir una cabecera de control de caché.

Me parece una manera elegante mediante el uso de una anotación de la costumbre y la creación de un interceptor que CXF leer esta anotación y añadir la cabecera.

Así que, primero, crear una anotación CacheControl

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

A continuación, añadir esta anotación a su método de operación CXF (interfaz o aplicación que funciona tanto si se utiliza una interfaz)

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

A continuación, crear un interceptor CacheControl que se encargará de la anotación y añadir la cabecera de su respuesta.

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

Finalmente configurar CXF utilizar su interceptor, se puede encontrar toda la información necesaria aquí: http: //cxf.apache.org/docs/interceptors.html

Esperamos que le ayude.

Loïc

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top