缓存如何在JAX-RS中运行?

Cha*_*han 11 java web-services http jax-rs http-caching

假设我使用@GET方法调用以下Web服务:

@GET
@Path(value = "/user/{id}")
@Produces(MediaType.APPLICATION_JSON)
public Response getUserCache(@PathParam("id") String id, @Context HttpHeaders headers) throws Exception {
    HashMap<String, Object> map = new HashMap<String, Object>();
    map.put("id", id);
    SqlSession session = ConnectionFactory.getSqlSessionFactory().openSession();
    Cre8Mapper mapper = session.getMapper(Cre8Mapper.class);

    // slow it down 5 seconds
    Thread.sleep(5000);

    // get data from database
    User user = mapper.getUser(map);

    if (user == null) {
        return Response.ok().status(Status.NOT_FOUND).build();
    } else {
        CacheControl cc = new CacheControl();
        // save data for 60 seconds
        cc.setMaxAge(60);
        cc.setPrivate(true);
        return Response.ok(gson.toJson(user)).cacheControl(cc).status(Status.OK).build();
    }
}   
Run Code Online (Sandbox Code Playgroud)

为了实验,我在从数据库中获取数据之前5秒放慢当前线程的速度.
当我使用Firefox海报呼叫我的网络服务时,在60秒内它在第2次,第3次呼叫等情况下似乎要快得多,直到它超过60秒.
但是,当我将URI粘贴到浏览器(Chrome)时,它似乎每次都会减慢5秒.我真的很困惑这种技术实际上是如何实现缓存的.这是我的问题:

  1. POSTER是否实际查看标题max-age并决定何时获取数据?
  2. 在客户端(web,android ....),当访问我的Web服务时,我是否需要检查标题然后手动执行缓存或浏览器已经缓存了数据本身?
  3. 有没有办法避免每次从数据库中获取数据?我想我必须以某种方式将我的数据存储在内存中,但它可能会耗尽内存吗?
  4. 在本教程中 JAX-RS缓存教程:缓存实际上如何工作?第一行总是从数据库中获取数据:

    预订myBook = getBookFromDB(id);

那么如何将其视为缓存?除非代码不按上/下顺序执行.

    @Path("/book/{id}")
    @GET
    public Response getBook(@PathParam("id") long id, @Context Request request) {
        Book myBook = getBookFromDB(id);
        CacheControl cc = new CacheControl();
        cc.setMaxAge(86400);
        EntityTag etag = new EntityTag(Integer.toString(myBook.hashCode()));        
        ResponseBuilder builder = request.evaluatePreconditions(etag);
        // cached resource did change -> serve updated content
        if (builder == null){
            builder = Response.ok(myBook);
            builder.tag(etag);
        }
        builder.cacheControl(cc);
        return builder.build();
    } 
Run Code Online (Sandbox Code Playgroud)

inv*_*ant 8

根据您的问题,我看到您将客户端缓存(http)与服务器端缓存(数据库)混合在一起.我认为导致这种情况的根本原因是你在firefox和chrome中观察到的不同行为我将首先尝试清除它

当我使用Firefox海报呼叫我的网络服务时,在60秒内它在第2次,第3次呼叫等情况下似乎要快得多,直到它超过60秒.但是,当我将URI粘贴到浏览器(Chrome)时,它似乎每次都会减慢5秒.

示例:

 @Path("/book")
    public Response getBook() throws InterruptedException {
        String book = " Sample Text Book";
        TimeUnit.SECONDS.sleep(5); // thanks @fge
        final CacheControl cacheControl = new CacheControl();
        cacheControl.setMaxAge((int) TimeUnit.MINUTES.toSeconds(1)); 
        return Response.ok(book).cacheControl(cacheControl).build();
    }
Run Code Online (Sandbox Code Playgroud)

我有一个安静的web服务,并且正在运行和url

http://localhost:8780/caching-1.0/api/cache/book - GET
Run Code Online (Sandbox Code Playgroud)

FireFox:

我第一次访问url时,浏览器向服务器发送了请求,并通过缓存控制头获得了响应.

fiefox initital req

在60秒内使用第二个请求(使用回车):这次firefox没有去服务器获取响应,而是从缓存加载数据

在此输入图像描述

60秒后的第三次请求(使用回车):

这次firefox向服务器发出请求并得到了响应.

使用刷新的第四个请求(F5或ctrl F5):

如果我在上一次请求的60秒内刷新页面(而不是点击输入),则firefox没有从缓存加载数据,而是在请求中向服务器发出请求

在此输入图像描述

Chrome:

60秒内的第二次请求(使用回车):这次chrome再次向服务器发送请求而不是从缓存加载数据,并且在请求中添加了header cache-control ="max-age = 0"

汇总结果:

由于chrome以不同的方式响应进入点击,你在firefox和chrome中看到了不同的行为,它与jax-rs或你的http响应无关.总结客户端(firefox/chrome/safari/opera)将在缓存控制中缓存指定时间段内的数据,除非时间到期或我们进行强制刷新,否则客户端不会向服务器发出新请求.

我希望这能澄清你的问题1,2,3.

4.在本教程中,JAX-RS缓存教程:缓存实际上如何工作?第一行总是从数据库中获取数据:

预订myBook = getBookFromDB(id);

那么如何将其视为缓存?除非代码不按上/下顺序执行.

你所提到的例子不是谈论最小化数据库调用而是关于通过网络保存带宽,客户端已经有数据及其与服务器的检查(重新验证)如果数据是否更新,如果数据没有更新则响应你'重新发送实际实体.


sha*_*zhu 1

  1. 是的。

  2. 使用 Firefox 或 Chrome 等浏览器时,您无需担心 HTTP 缓存,因为现代浏览器会处理它。例如,使用 Firefox 时它使用内存缓存。使用 Android 时,这取决于您与源服务器的交互方式。根据WebView的说法,它实际上是一个浏览器对象,但是如果使用HTTPClient,则需要您自己处理HTTP缓存。

  3. 这与 HTTP 缓存无关,而是与服务器端逻辑有关。常见的答案是使用数据库缓存,这样您就不需要在每个 HTTP 请求中访问数据库。

  4. 实际上,JAX-RS 只是为您提供了使用 HTTP 缓存标头的方法。您需要使用 CacheControl 和/或 EntityTag 来执行基于时间的缓存和条件请求。例如,当使用 EntityTag 时,构建器将处理您永远不需要担心的响应状态代码 304。