1

I'm using a custom web server built on NanoHTTPD, that I've added caching features to. There's only one part in the code that could throw a 304 Not Modified response:

           if(isNotModified(f,header,parms)){// if requested file has not been modified, let's make the browser use it's cache
                Response r= new Response( Response.Status.NOT_MODIFIED, MIME_PLAINTEXT,(String)null,null);
                //r.addHeader(key,val);
                r.addHeader("Last-Modified",""+f.lastModified());//FIXME: doesnt work with wget + prob others as well
                r.addHeader("ETag",f.getPath()+f.lastModified());

                return r;
            }

isNotModified method:

/**
 * check if the file has been modified since the last time client requested it
 * */
public boolean isNotModified(File ff,Properties header, Properties params){
    if(params.getProperty("bust")!= null ||params.getProperty("cachebust")!=null)
        return false; 
    if(ff.getName().endsWith(".pg"))
        return false;
    if(ff.getPath().indexOf("/api/")>=0)
        return false;
    if("no-cache".equalsIgnoreCase(header.getProperty("cache-control")))
        return false;

    String mod = header.getProperty("if-modified-since");//names are converted to lowercase fwiw

    if(mod==null)//this should happen whenever browser sends no if-modified-since
        return false;

    try{
        long l = Long.parseLong(mod);
        if(ff.lastModified()<=l)
            return true;
    }catch(Exception ex){
        ex.printStackTrace();
    }

    return false;
}

For some reason I'm still getting 304 with (at least) Chrome even though there is no If-Modified-Since specified in the header (or anything related to caching). This leads to the browser interpreting the resource as an empty string and breaking things.

Seppo420
  • 2,041
  • 2
  • 18
  • 37

2 Answers2

2

The response code 304 is used by Chrome to indicate the response was served from a local cache instead of fetched from the server. As this is not a real HTTP response, but a faux object, it may confuse a lot of developers. It properties differ from genuine response objects. This is especially case with AJAX requests.

The suggested workaround is to send Expires header instead of Last-modified so that you have exact control when the browser users local cache and when the browser makes a request to the server.

With the case of Expires header

  • You will get faux HTTP 304 response until the time in Expires header is reached

  • After this the browser makes a real request to the server

Mikko Ohtamaa
  • 82,057
  • 50
  • 264
  • 435
  • What evidence do you have for this? When resources come from the local cache, the Size column in the developer tools network inspector reports "(from cache)". It doesn't do it for 304 responses. – Rupert Rawnsley Jul 31 '14 at 14:06
  • I am not sure why you are asking and it would be too cumbersome for me to set up a repeatable test environment just to answer for your comment with evidence. However I can post you a screenshot when I encounter this issue again. – Mikko Ohtamaa Jul 31 '14 at 14:27
  • I'm debugging an issue where Chrome sends Is-Modified-Since requests for resources that were marked with Cache-Control:max-age=. The server responds with a 304 and I'm pretty sure it is a genuine network transaction, because there are other resources that are marked as (from cache). I appreciate that you don't want to reproduce it now, but please update if you see it again. – Rupert Rawnsley Jul 31 '14 at 15:45
  • Also I am pretty sure Chrome team might modify this behavior from time to time. However I definitely did not see the request hitting the server in my case. – Mikko Ohtamaa Aug 01 '14 at 07:35
0

I fixed all the headers and added an Expires header w/o any help, but adding this did the trick:

if("no-cache".equalsIgnoreCase(header.getProperty("pragma")))
        return false;
Seppo420
  • 2,041
  • 2
  • 18
  • 37