如何使用Jersey缓存响应?

chi*_*iru 9 java rest jersey

我正在尝试使用Jersey开发restful API.我有一个特定的get操作的GET API,我的GET从同一个客户端同时进行.是否可以缓存响应?任何指针都表示赞赏.

谢谢

The*_*bit 10

您可以使用CacheControl,eTag - 按照下面的示例代码

// In your jersey method
    final EntityTag eTag = new EntityTag(resource.getId() + "_" +
     resource.getLastModified().getTime());
    final CacheControl cacheControl = new CacheControl();
    cacheControl.setMaxAge(-1);

    ResponseBuilder builder = request.evaluatePreconditions(
         resource.getLastModified(), eTag);

    // the resoruce's information was modified, return it
    if (builder == null) {
         builder = Response.ok(resource);
    }

    // the resource's information was not modified, return a 304

    return builder.cacheControl(cacheControl).lastModified(
         resource.getLastModified()).tag(eTag).build();
Run Code Online (Sandbox Code Playgroud)

替换resource为您的Resource实例.

  • 也就是说,它的缓存永远但服务器可以说是否基于e-tag修改了资源,因此客户端/浏览器可以从缓存中使用它 (2认同)

dur*_*dur 7

解决方案摘要:

  1. 请求作为方法参数

    接口:

    @Path("myentity")
    public interface MyEntityResource
    
        @GET
        @Produces(MediaType.APPLICATION_JSON)
        public Response getMyEntity(@Context final Request request);
    }
    
    Run Code Online (Sandbox Code Playgroud)

    执行:

    public class MyEntityResourceImpl implements MyEntityResource
    
        @Override
        public Response getMyEntity(final Request request) {
    
            final MyEntity myEntity = ... // load entity
            final String eTagValue = ... // calclutate value of ETag
    
            final EntityTag eTag = new EntityTag(eTagValue);
    
            ResponseBuilder responseBuilder = request.evaluatePreconditions(eTag);
    
            if (responseBuilder == null) {
                return Response.ok(user).tag(eTag).build();
            }
    
            return responseBuilder.build();
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

    缺点:

    • 实现细节Request暴露

    • 返回类型Reponse是通用的

    • 在WADL中缺少返回类型的语法

    • 客户代理与不必要的参数Request

  2. 请求作为实例变量

    接口:

    @Path("myentity")
    public interface MyEntityResource
    
        @GET
        @Produces(MediaType.APPLICATION_JSON)
        public Response getMyEntity();
    }
    
    Run Code Online (Sandbox Code Playgroud)

    执行:

    public class MyEntityResourceImpl implements MyEntityResource
    
        @Context
        private Request request
    
        @Override
        public Response getMyEntity() {
    
            final MyEntity myEntity = ... // load entity
            final String eTagValue = ... // calclutate value of ETag
    
            final EntityTag eTag = new EntityTag(eTagValue);
    
            ResponseBuilder responseBuilder = request.evaluatePreconditions(eTag);
    
            if (responseBuilder == null) {
                return Response.ok(user).tag(eTag).build();
            }
    
            return responseBuilder.build();
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

    缺点:

    • 返回类型Reponse是通用的

    • 在WADL中缺少返回类型的语法

    • 依赖注入@Context很复杂,请参阅/sf/ask/2326831041/

  3. ShallowEtagHeaderFilter作为Web过滤器

    web.xml中:

    <filter>
        <filter-name>etagFilter</filter-name>
        <filter-class>org.springframework.web.filter.ShallowEtagHeaderFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>etagFilter</filter-name>
        <url-pattern>/api/*</url-pattern>
    </filter-mapping>
    
    Run Code Online (Sandbox Code Playgroud)

    接口:

    @Path("myentity")
    public interface MyEntityResource
    
        @GET
        @Produces(MediaType.APPLICATION_JSON)
        public MyEntity getMyEntity();
    }
    
    Run Code Online (Sandbox Code Playgroud)

    执行:

    public class MyEntityResourceImpl implements MyEntityResource
    
        @Override
        public MyEntity getMyEntity() {
    
            final MyEntity myEntity = ... // load entity
            return myEntity;
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

    缺点:

    • 糟糕的服务器性能,请参阅JavaDoc

    • 仅适用于未提交的响应

    • 没有弱ETag的支持

  4. 自定义WriterInterceptor作为JAX-RS拦截器

    拦截器:

    public class CustomInterceptor implements WriterInterceptor {
    
        @Context
        private Request request;
    
        @Override
        public void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException {
    
            OutputStream old = context.getOutputStream();
    
            ByteArrayOutputStream buffer = new ByteArrayOutputStream();
    
            try {
    
                context.setOutputStream(buffer);
                context.proceed();
    
                byte[] entity = buffer.toByteArray();
    
                String etag = ... // calclutate value of ETag
                context.getHeaders().putSingle(HttpHeaders.ETAG, etag);
    
                ResponseBuilder responseBuilder = request.evaluatePreconditions(eTag);
    
                if (responseBuilder == null) {
                     throw new WebApplicationException(responseBuilder.status(Response.Status.NOT_MODIFIED).header(HttpHeaders.ETAG, etag).build());
                }
    
                old.write(entity);
    
            } finally {
                context.setOutputStream(old);
            }
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

    另请参见:ServerCacheInterceptor(Resteasy)

    接口:

    @Path("myentity")
    public interface MyEntityResource
    
        @GET
        @Produces(MediaType.APPLICATION_JSON)
        public MyEntity getMyEntity();
    }
    
    Run Code Online (Sandbox Code Playgroud)

    执行:

    public class MyEntityResourceImpl implements MyEntityResource
    
        @Override
        public MyEntity getMyEntity() {
    
            final MyEntity myEntity = ... // load entity
            return myEntity;
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

    缺点:

    • 没有针对Jersey的预定义拦截器

    • 服务器性能不佳

    • 没有弱ETag的支持

    • 丑陋的解决方法 WebApplicationException