1

I added a custom caching behavior to my application, similar to what Thierry has proposed in this article. For every CSS, JS and HTML file server in my static content I am adding the two following headers:

// Added by me
ETag: "0c635aa7113262fac7606da2432e00f5" // md5(last_mod_date_of_file)
Cache-Control: max-age=31536000 // one year

// Automatically added by Restlet (probably Directory class?)
Date: Wed, 09 Nov 2016 11:50:53 GMT
Expires: Wed, 09 Nov 2016 12:00:53 GMT
Last-Modified: Wed, 09 Nov 2016 17:30:56 GMT

This works fine, however I have noticed that after deploying the code on test server and hitting F5 in Chrome, I fetch the entire body of response once again (with HTTP 200 returned).

I've noticed that those requests are using proper headers too:

Cache-Control:max-age=0
If-Modified-Since: Wed, 09 Nov 2016 17:30:56 GMT
If-None-Match: "0c635aa7113262fac7606da2432e00f5"

My question is, should I do any manual verifications of If-None-Match header in my server filter and return 304 response then? Or is that handled by Restlet?

Note: what's a bit strange in this issue is the fact that it seemed to work properly on my local development environment. I'm also a little bit confused as to why Expires is set by Restlet to a date before Last-Modified. I'll try to debug if this is the root of evil, but it doesn't invalidate my question about manual setting of 304 status and checking ETags on the server.

ŁukaszBachman
  • 32,989
  • 10
  • 61
  • 69
  • A typically scenario is to have a caching reverse proxy between the browser and your Java application. In this case the 304 is handled by it and you don't need to bother inside the application. Take care, because the edge server might interpret the headers not the same as the browser or the HTTP standard defines. E.g. NGINX is highly (miss)configurable. – cruftex Nov 16 '16 at 17:24
  • 1
    From the header above, Last-Expires is 10 minutes after the current time. Actually the last-modified time seams wrong. Maybe different times or zones on build and production? – cruftex Nov 16 '16 at 17:26

1 Answers1

2

Ok, so I've been able to figure this out and I'm posting answers below.

Should I do any manual verification of If-None-Match header in my server filter and return 304 response then?

No, you don't have to do that yourself manually. This is automatically being handled by Restlet (DirectoryServerResource takes care of that).

What was the problem then?

The problem was indeed with the Last-Modified header being set to a future date. This has happened because my production server was in UTC-8 Time Zone, whereas I'm developing in UTC+1.

How did I fix it?

It required getting acquainted with Restlet API, but the solution was trivial then. I made sure that when my application is started it reads File Last Modified property of my application directory from Operating System, as this is the value I wanted to use in Last-Modified header. Now, you can't just set this header on a response in a Filter, as the automatic handling of HTTP caching headers happens before that in mentioned DirectoryServerResource class. So the solution is the following:

Create a class which extends DSR (giving you all the automatic caching handling for free) and modify its handle() method so that Last-Modified header is set before this logic kicks in:

 public class WebAssetsResource extends DirectoryServerResource {
    @Override
    public Representation handle() {
        Date desiredDate = ...; // I read this from File System
        getInfo().setModificationDate(desiredDate);
        return super.handle(); // Automatic logic will use desired date
    }
 }

Now, make sure that your newly created resource is used by custom Directory class.

public class CachedWebAssetsDirectory extends Directory {
    public CachedWebAssetsDirectory(Context context, Reference rootLocalReference) {
        super(context, rootLocalReference);
        setTargetClass(WebAssetsResource.class); // Needed so that Restlet will use our implementation of a ServerResource to serve static files
    }
}

After that you can use CachedWebAssetsDirectory as you wish, building any custom filters on top of that.

ŁukaszBachman
  • 32,989
  • 10
  • 61
  • 69