Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does caching work in JAX-RS?

Suppose I have the following web service call using @GET method:

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

To experiment, I slow down the current thread 5 seconds before fetching data from my database.
When I call my web service using Firefox Poster, within 60 seconds it seemed much faster on the 2nd, 3rd calls and so forth, until it passed 60 seconds.
However, when I paste the URI to a browser (Chrome), it seemed to slow down 5s everytime. And I'm really confused about how caching is actually done with this technique. Here are my questions:

  1. Does POSTER actually look at the header max-age and decide when to fetch the data?
  2. In client side (web, android....), when accessing my web service do I need to check the header and then perform caching manually or the browser already cached the data itself?
  3. Is there a way to avoid fetching data from the database every time? I guess I would have to store my data in memory somehow, but could it potentially run out of memory?
  4. In this tutorial JAX-RS caching tutorial: How does caching actually work? The first line always fetch the data from the database:

    Book myBook = getBookFromDB(id);

So how it is considered cached? Unless the code doesn't execute in top/down order.

    @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();
    } 
like image 601
Chan Avatar asked Jul 05 '13 05:07

Chan


People also ask

How does webserver cache work?

Web caching works by caching the HTTP responses for requests according to certain rules. Subsequent requests for cached content can then be fulfilled from a cache closer to the user instead of sending the request all the way back to the web server.

How do I caching in RESTful web services?

Cache-Control Header Indicates that resource is cacheable only by the client and the server, no intermediary can cache the resource. Indicates that a resource is not cacheable. Indicates the caching is valid up to max-age in seconds. After this, client has to make another request.

Is caching possible in REST API?

Caching in REST APIs POST requests are not cacheable by default but can be made cacheable if either an Expires header or a Cache-Control header with a directive, to explicitly allows caching, is added to the response. Responses to PUT and DELETE requests are not cacheable at all.

What is the purpose of using JAX-RS?

JAX-RS is a Java programming language API designed to make it easy to develop applications that use the REST architecture. The JAX-RS API uses Java programming language annotations to simplify the development of RESTful web services.


2 Answers

From your questions i see that you're mixing client side caching(http) with server side caching(database). I think the root cause for this is the different behavior you observed in firefox and chrome first i will try to clear this

When I call my web service using Firefox Poster, within 60 seconds it seemed much faster on the 2nd, 3rd calls and so forth, until it passed 60 seconds. However, when I paste the URI to a browser (Chrome), it seemed to slow down 5s everytime.

Example :

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

I have a restful webservice up and running and url for this is

http://localhost:8780/caching-1.0/api/cache/book - GET

FireFox :

First time when i accessed url ,browser sent request to server and got response back with cache control headers.

fiefox initital req

Second Request with in 60 seconds (using Enter) : This time firefox didn't went to server to get response,instead its loaded data from cache

enter image description here

Third Request after 60 seconds (using Enter) :

this time firefox made request to server and got response.

Fourth Request using Refresh (F5 or ctrl F5) :

If i refresh page ( instead of hitting enter) with in 60 seconds of previous request firefox didn't load data from cache instead it made request to server with special header in request

enter image description here

Chrome :

Second Request with in 60 seconds (using Enter ) : This time chrome sent request again to server instead of loading data from cache ,and in request it added header cache-control = "max-age=0"

Aggregating Results :

As chrome responding differently to enter click you saw different behavior in firefox and chrome ,its nothing do with jax-rs or your http response . To summarize clients (firefox/chrome/safari/opera) will cache data for specified time period in cache control , client will not make new request to server unless time expires or until we do a force refresh .

I hope this clarifies your questions 1,2,3.

4.In this tutorial JAX-RS caching tutorial: How does caching actually work? The first line always fetch the data from the database:

Book myBook = getBookFromDB(id);

So how it is considered cached? Unless the code doesn't execute in top/down order.

The example you referring is not talking about minimizing data base calls instead its about saving band width over network ,Client already has data and its checking with server(revalidating) if data is updated or not if there is no update in data in response you're sending actual entity .

like image 165
invariant Avatar answered Sep 20 '22 21:09

invariant


  1. Yes.

  2. When using a browser like firefox or chrome, you don't need to worry about HTTP cache because modern browsers will handle it. For example, it uses in-memory cache when using Firefox. When using Android, it depends on how you interact with the origin server. According to WebView, it's actually a browser object, but you need to handle HTTP cache on your own if using HTTPClient.

  3. It's not about HTTP caching but your server-side logic. the common answer is using database cache so that you don't need to hit database in every HTTP request.

  4. Actually JAX-RS just provides you ways to work with HTTP cache headers. you need to use CacheControl and/or EntityTag to do time based cache and conditional requests. for example, when using EntityTag, the builder will handle response status code 304 which you never need to worry about.

like image 29
shawnzhu Avatar answered Sep 21 '22 21:09

shawnzhu