Does Firefox cache javascript and use it without a request if there is a querystring in the path?

3.8k Views Asked by At

What I would like to do is append a query string on the end of the javascript path so that whenever my application is updated to a new version, the javascript is downloaded. As long as the query string is the same however, I want it to keep using the cached version without doing a http request to check to see if the script has changed.

The way I am accomplishing this in PHP is to read from the CVS tag. When I am building the HTML to output, I read the CVS tag and use that to append to the end of the javascript path so that it creates a script tag that looks like this:

<script src="javascript/messages/shipments.js?TPRSAPPS-DEV2_090828145712237-BRANCH" type="text/javascript"></script>

As long as the app hasn't changed, the tag will stay the same and therefore the query string will also. The browser should cache the JS and not do a network request at all because the expire date is far future. Each time the app is updated, that query string will change and the browser should download it.

This works great in IE8. My problem is with Firefox. Firefox caches the files, but the next time I load the page Firebug shows a 304 response, indicating that it still did a network request for the file and then found that it hadn't changed.

So my question is, does firefox ignore the expires header and cache of javascript when there is a query string?

Related: what does firefox decide not to cache? Apparently Rails does something similar. But this doesn't answer my question.

Here is the response I am getting back on this file:

https://appdev.prsx.net/~jhargett/PRSApps-Motorlog/javascript/menuReader.js?TPRSAPPS-DEV2_090828145712237-BRANCH-DIFFERENT

HTTP/1.1 304 Not Modified
Date: Mon, 03 Oct 2011 18:35:26 GMT
Server: Apache/2.2.3 (Red Hat)
Connection: close
Etag: "179010-3f8-49a9a74334200"
Vary: Accept-Encoding

The Cache tab in Firebug says:

Last Modified   Mon Oct 03 2011 13:35:26 GMT-0500 (Central Daylight Time)
Last Fetched    Mon Oct 03 2011 13:35:26 GMT-0500 (Central Daylight Time)
Expires Fri Oct 28 2011 18:33:31 GMT-0500 (Central Daylight Time)
Data Size   345
Fetch Count 12
Device  disk
4

There are 4 best solutions below

2
On BEST ANSWER

The logic Firefox uses to decide whether to make a conditional GET given a cached response is like so:

  1. If there is a relevant Vary header, revalidate.
  2. If this request is supposed to be force-loaded from cache, do not revalidate.
  3. If this request has the "always validate" flag, revalidate.
  4. If this request has the "never validate" flag then revalidate only if this is a no-store response or SSL no-cache response.
  5. If the response status code is not cacheable or the response is no-cache or no-store or if the expiration time is before the Date of the response, revalidate.
  6. If there is a query paramater and the response does not have an explicit Expires or max-age, revalidate.
  7. If the response expiration time is in the past, revalidate (unless the "only revalidate once per session user preference is set").

So for your case, there should not be a conditional GET, assuming you actually set expires or max-age information on your 200 response.

That said, some of the tools that try to trace HTTP information for Firefox actually affect the revalidation behavior, so you may be running into that.

I recommend creating a log following the steps in https://developer.mozilla.org/en/HTTP_Logging which will incidentally tell you exactly why a conditional GET is being done, if you can find the right part of the log (search for "nsHttpChannel::CheckCache enter" for the logging from the function that implements the above logic).

1
On

What you are looking at is something different than actually downloading the file, and then say it has not changed.

Firefox does do a HTTP request to get the file information, not the file itself. This actually means firefox is doing this smarter then IE is doing.

The request firefox does is just a couple of bytes large (filesize, date etc). so no matter what the name, firefox caches it (unless disabled). If the file itself changes, firefox decides to re-download the file.

The thing you are pointing out is actually correct behavior.

0
On

As explained in Boris' answer, one of conditions that trigger conditional request is presence of Vary header. You usually don't want to remove vary on Accept-Encoding, but what you can do and what is good thing to do in case when you have URL versioning, is to leave the browser with nothing to revalidate against. In your case it's Etag header. It can as well be Last-Modified header. Example code for varnish to do that for you may look like this:

  sub vcl_recv {
  [..]
        if (req.url ~ "\?v=\w+$") {
          set req.http.X-Versioned = "1";
        }
  [..]
  }

  sub vcl_deliver {
  [..]
        if (req.http.X-Versioned) {
          unset resp.http.Etag;
        }
  [..]
  }
2
On

If you want to be absolutely sure that your file will get reloaded, it's better to put the version number/cache buster string directly in the file name. So you'd have something like shipments_v2.js or shipments_(unix_timestamp).js. This will take care of proxies and any other kind of caching mechanisms.