express icon indicating copy to clipboard operation
express copied to clipboard

default no-cache headers

Open dlants opened this issue 5 years ago • 3 comments

Hi there!

By default, express does not serve no-cache headers on routes, so for instance:

import * as express from 'express'

const app = express()
app.get('/', (_req, res) => {
  res.send('Hello')
})

app.listen(3000)

Results in the following:

curl -I localhost:3000
HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: text/html; charset=utf-8
Content-Length: 5
ETag: W/"5-9/+ei3uy4Jtwk1pdeF4MxdnQq/A"
Date: Thu, 15 Nov 2018 22:53:08 GMT
Connection: keep-alive

This is missing Cache-Control: no-cache, Pragma: no-cahe or Expires: 0 headers that would inform the browser that the result of the request should not be cached.

My suggestion is to serve these files with no-cache headers by default, like serve-static. This will reduce the chance that folks will forget to configure it, and end up potentially having clients hang on to stale code.

(this is an issue I've recently run into on my project -- it seems that sometimes browsers do cache such responses when no cache headers are provided)

Thanks for your hard work!

dlants avatar Nov 15 '18 23:11 dlants

But we want web browsers to cache the content when possible by default. They should still be sending a conditional request due to the etag. What browser are you using and can you put together a reproduction case that demonstrates the browser not seeing the new content?

dougwilson avatar Nov 15 '18 23:11 dougwilson

Ah, that clarifies things! I didn't know about the Etag directive, and missed it in the output above. Thanks!

I think that totally makes sense as the default setting, and hopefully this issue will help some others that are following the same red herring as me. It's likely that something about our CDN is interfering with proper handling of the Etag header... since we're seeing chrome (69, 70) on ChromeOs and Windows 10 have the stale code issue.

dlants avatar Nov 15 '18 23:11 dlants

One thing to note is that no-cache does not mean "do not cache" - that would be no-store, rather it means "do not serve this content from the cache without first validating it's freshness on the server".

And because @dlants didn't tell the client to first validate with the server, browsers have to rely on their own freshness heuristics in which case the content may be cached for some time.

I found this article which goes to the extent of looking at the source code of some of the major browsers, and verifies that content without cache-control or Expires is cached for "10% of the time since the object was last modified (provided that a Last-Modified header was returned)".

So if you have users downloading a web page (which does not use no-cache or a low max-age) that is still cached for 10% of the time since it was last modified, but has been updated since, breakage should be expected. This of course, should only be the case for documents, sub resources should preferably use file name versioning and a long max-age / immutable directive.

Malvoz avatar Jul 02 '19 15:07 Malvoz