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

发布于 2024-08-18 13:57:55 字数 490 浏览 10 评论 0原文

CXF 文档提到缓存为 高级 HTTP

CXF JAXRS 通过处理 If-Match、If-Modified-Since 和 ETags 标头来支持许多高级 HTTP 功能。 JAXRS 请求上下文对象可用于检查先决条件。还支持 Vary、CacheControl、Cookies 和 Set-Cookies。

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

The CXF documentation mentions caching as Advanced HTTP:

CXF JAXRS provides support for a number of advanced HTTP features by handling If-Match, If-Modified-Since and ETags headers. JAXRS Request context object can be used to check the preconditions. Vary, CacheControl, Cookies and Set-Cookies are also supported.

I'm really interested in using (or at least exploring) these features. However, while "provides support" sounds really interesting, it isn't particularly helpful in implementing such features. Any help or pointers on how to use If-Modified-Since, CacheControl or ETags?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

野却迷人 2024-08-25 13:57:55

实际上,答案并不特定于 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();
}

Actually, the answer isn't specific to CXF - it's pure 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();
}
潇烟暮雨 2024-08-25 13:57:55

随着即将推出的 JAX-RS 2.0,将可以以声明方式应用 Cache-Control,如 http://jalg.net/2012/09/declarative-cache-control-with-jax-rs-2-0/

您至少已经可以测试这个与泽西岛。但不确定 CXF 和 RESTEasy。

With the forthcoming JAX-RS 2.0 it will be possible to apply Cache-Control declaratively, as explained in http://jalg.net/2012/09/declarative-cache-control-with-jax-rs-2-0/

You can already test this at least with Jersey. Not sure about CXF and RESTEasy though.

内心荒芜 2024-08-25 13:57:55

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

希望它会有所帮助。

卢伊克

CXF didn't implements dynamic filtering as explained here : http://www.jalg.net/2012/09/declarative-cache-control-with-jax-rs-2-0

And if you use to return directly your own objects and not CXF Response, it's hard to add a cache control header.

I find an elegant way by using a custom annotation and creating a CXF Interceptor that read this annotation and add the header.

So first, create a CacheControl annotation

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

Then, add this annotation to your CXF operation method (interface or implementation it works on both if you use an interface)

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

Then create a CacheControl interceptor that will handle the annotation and add the header to your response.

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

Finally configure CXF to use your interceptor, you can find all the needed information here : http://cxf.apache.org/docs/interceptors.html

Hope it will help.

Loïc

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文