8

I have setup a simple static server using express.

var location = path.join(__dirname, 'public');
app.use(express.static(location, { cacheControl: true, setHeaders: function(res, path) { 
    res.setHeader("Cache-Control","max-age=0,must-revalidate");  
} }));

The request header is sent with If-None-Match and If-Modififed-Since and I can also see 304 Not Modified in the response in Chrome if I reload the page without modifying the files. And I get a 200 OK if I modify one of the files.

But why is my Chrome network tab showing the size of the file downloaded instead of saying (from memory cache) when the status code is 304 Not Modified ?

I was expecting the files to be loaded from cache if its not modified and served up from the server if modified.

Appreciate any help and guidance.

anivas
  • 6,437
  • 6
  • 37
  • 45

2 Answers2

20

@sBanda described the situation very well. Receiving a 304 is expected since the specified cache-control policy states the file as stale, yet the ETag check shows it hasn't changed.

So you get the 304 because you could have not requested the specific resource, yet you did, wasting bandwidth and cpu load.

What you should do to avoid it is something like this:

const express       = require('express');


const server        = express();
const oneHour       = 3600000;    // 3600000msec == 1hour

server.use(express.static('www', { maxAge: oneHour })); // Client-side file caching

server.get('/', function(req, res) {
  res.sendFile(__dirname + '/index.html');
});

server.listen(8080);

Source

maninak
  • 2,633
  • 2
  • 18
  • 33
  • But setting it to oneHour will reload the file from the server and reset its cache only after an hour, I want the cache to be reloaded to the new files if its modified within the hour as well – anivas Jun 17 '17 at 19:04
  • 5
    Ahaa, now we're getting somewhere ;) Say hello to the [`Cache Invalidation`](https://halfelf.org/wp-content/uploads/sites/2/2016/10/jeff-atwood.png) problem, one as old, as probably computer science itself. Well what web developers usually do is set the maxAge a huge value (1 year) and when a file changes, then they rename it `main.css` -> `main_v2.css`. And because this is getting hard fast, we usually append the filename with the hash value of the file `main_4abed1c996f46e1b2ad61757af46ece4.css` automatically with build tools like gulp, so that any change automatically invalidates the cache. – maninak Jun 17 '17 at 19:17
  • But this has already gotten beyond the scope of your original question and there's plenty of well-written resources available online, you should best close this question if it has been answered and if you still need help on cache invalidation, then make a new one. :) – maninak Jun 17 '17 at 19:19
  • 1
    Upon inspecting in Fiddler the 304 response only had the header and not the body, am I right to assume the content was not transferred from the server to the browser in case of 304. – anivas Jun 18 '17 at 15:11
  • Yes, the content has not been transfered. But the ETags have been sent and evaluated. This wastes resources and most importantly delays the loading of resources your website actually needs, because of the roundrtrip time delay holding up the browser's network threads for no useful reason. This is especially bad if you are browsing on 3G or 2G networks where you want a website to make as few fetch requests as possible because there is a *very* big delay in response, even if just to return a 304. – maninak Jun 18 '17 at 16:11
5

When the browser puts something in its cache, it also stores the Last-Modified or ETag header from the server. This tag is then used to send a request with the If-Modified-Since or If-None-Match header witch in effect tells server to send 304 if the content still has that ETag.

In your case Chrome is doing a request to ask the server should it use its cache there is an old post explaining this here.

You might want to check out this website about increasing application performance via HTTP Cache Headers.

sBanda
  • 379
  • 2
  • 8
  • I get all that and it does everything as expected. But even if the content has the same ETag and the server sends 304, I am expecting the browser to fetch from its cache not from the server again. – anivas Jun 17 '17 at 18:49
  • Browser needs to check is it gonna use the cache or is there a new file there to download. If you want it to be used from cache without having to check you should use **Expires** or **Cache-Control max age** – sBanda Jun 17 '17 at 18:52
  • I want it to be used from cache if not modified, else from the server if modified. – anivas Jun 17 '17 at 19:07