0

I have an issue where Chrome browsers do not reload updated javascripts.

This is because, in Chrome, the request is never sent to the server.

The other browsers I support (Firefox, Edge, Safari) work fine; this appears to be because they send an If-Modified-Since header.

The file is served as part of a collection of static assets. Everything is gzipped by nginx.

sites-available/default:

root /var/www;
index index.php index.html index.htm;
// some php stuff ...

A (maybe?) relevant line from /etc/nginx.conf

# Proxy cache
proxy_cache_path /var/tmp/nginxcache keys_zone=one:10m;

Curl output for a get on the javascript:

< HTTP/1.1 200 OK
* Server nginx/1.4.6 (Ubuntu) is not blacklisted
< Server: nginx/1.4.6 (Ubuntu)
< Date: Sun, 05 Aug 2018 11:52:44 GMT
< Content-Type: application/x-javascript
< Content-Length: 2350005
< Last-Modified: Sun, 05 Aug 2018 11:38:36 GMT
< Connection: keep-alive
< Vary: Accept-Encoding
< ETag: "5b66e1bc-23dbb5"
< Accept-Ranges: bytes

Is there a configuration in nginx that can persuade Chrome to do likewise? I have explored these answers: Setting expires headers for static content served from nginx and https://stackoverflow.com/questions/17251503/set-expires-to-max-for-all-images-of-all-servers-in-nginx/17253805#17253805 but my regex skills are rather poor, and the answers are quite old. Should I try:

location ~ \.js {
    expires 1d;
    add-header Pragma public
    add-header Cache-control "public"
}
minisaurus
  • 113
  • 1
  • 7
  • 1
    This is a harder problem than it seems. Look up "cache busting" and read the first 50-100 results. – Michael Hampton Aug 05 '18 at 12:48
  • Yes, this is what I've now done (I think!) - a build process that names the relevant javascript based on a hash, that I then have to update in index.html. . Thanks for the tip. I wanted to double-check - index.html never gets cached, right? – minisaurus Aug 06 '18 at 13:15
  • That depends on what you have configured in nginx, whether you use https, etc. For index.html in a single page app I suggest setting a relatively short max-age. But that's a tradeoff between reducing load to the server and being able to deploy changes quickly. – Michael Hampton Aug 06 '18 at 13:17
  • Ok, thanks Michael - it is https, and also a PWA. Think I've sorted it - I added a location blah { expires 1d; } and am now getting Cache-Control: max-age=86400 with curl. I'll increase this when the app has "stabilised", ha-ha. So, just to try and understand better, if one doesn't configure anything, does nginx cache indefinitely by default? – minisaurus Aug 06 '18 at 14:31
  • If you don't send a Cache-Control header, the default is determined by the caching entity, e.g. the browser. For HTTP the default is `public`, and for HTTPS the default is `no-cache`. So you should always set a Cache-Control header. – Michael Hampton Aug 06 '18 at 14:33
  • Ok. So I need to add a ' add-header Cache-control "public" ' to the location {} block? – minisaurus Aug 06 '18 at 20:01
  • Or you could set a `max-age` or whatever makes sense for your application. – Michael Hampton Aug 06 '18 at 20:02
  • Thanks for your help! Seems to be working, I've posted an answer (do let me know if I've messed up!) – minisaurus Aug 08 '18 at 07:28

1 Answers1

0

Thanks to help from @Michael Hampton, I added this location block to the server:

    location ~* \.(:manifest|html?|json)$ {
        expires 1d;
    }

So my index.html expires after one day.

I also started building the app with gulp and gulp-rev to get a version hash on the app name, such as app-xyzz56464.js, which then sits in index.html.

minisaurus
  • 113
  • 1
  • 7