How to make browser cache assets with express.js - node.js

I want my assets to be cached by browser. So I use:
var oneDay = 86400000;
app.use(express.static('public', { maxAge: oneDay }));
So in response I see:
cache-control: public, max-age=86400000
But when assets are requested by browser it still makes request to server and usually gets 304 not modified response and only then takes version from cache.
In response I also see 'Etag' and 'Last-Modified' headers, maybe they for such behaviour? (any why I wasn't able to get read of Last-Modified header to check it.
If I understand correctly I max-age was set in response when downloading resource for the first time, then browser while the period (set by max-age) should take if from cache and not make any request to server.
What am I doing wrong?
I wonder how people serve static assets and index files in production with express.js?

Related

Browser doesn't cache http response

I have a http request /api/speakers/ and I want it to be cached by browser.
So I added Cache-Control to the request headers:
headers: {
'Cache-Control': 'public, must-revalidate, max-age=86400'
}
cache-control appears in request headers, but every time it requests it gets new data from response. I am testing without refreshing page, so that is not the problem.
What am I doing wrong? How to tell browser to cache request responses and not to request it next one day.
I thought that Cache-control should be sent by frontend, so the browser understands it and caches requests. It turned out that backend sends headers in response so browser can cache requests. In my case, backend written in Django used cache_page and now browser caches everything perfectly.

How to cache response from google drive API in NodeJS

I want to reproduce music files from google drive on a web page. I have the link for each file but the response cache headers for the calls are 'no-cache, no-store, max-age=0, must-revalidate" so it will never be saved on the browser cache. Is there any way to add cache to google drive files requests?
The problem:
When you use the drive link for a music file (mp3) https://drive.google.com/a/pucp.pe/uc?id=1kYYS9FZ9Vxif5WJM9ZQcY4SR35NMgoIE&export=download the GET API call receives a 302 code which generates a redirect to another URL, in this case, to 'https://doc-0o-28-docs.googleusercontent.com/docs/securesc/bgp95l3eabkkpccn0qi0qopvc4e7d4mq/us95e8ush1v4b7vvijq1vj1d7ru4rlpo/1556330400000/01732506421897009934/01732506421897009934/1kYYS9FZ9Vxif5WJM9ZQcY4SR35NMgoIE?h=14771753379018855219&e=download'. Each of these calls has no-cache in headers.
I tried using workbox (cache API) but I don't find a way to cache redirects, probably I need to cache both calls (the first GET and the redirect). However, if I use the redirected URL the caching works, but I don't have access to that URL until the first call is made.
I tried to use a proxy server from a NodeJS server
app.get("/test", (req, res) => {
try {
https.get(
URL,
function(response) {
res.writeHead(response.statusCode, {...response.headers,
"Cache-Control": "public, max-age=120",
"Expires": new Date(Date.now() + 120000).toUTCString() })
response.pipe(res);
}
);
} catch (e) {
console.log(e);
}
});
I tried using the first URL with no luck.
I tried using the redirect URL but I get a "Status Code: 302 Found"
One solution could be to download the file and serve it directly from my server but I will be missing the point of using the drive storage. I really want to use google drive storage and not duplicate all files on my server.
Is there a recommended way to do the caching for this case? maybe there is some google drive configuration that I'm missing. Or do you know another approach I could take in this case?
You should be able to cache redirected responses using Workbox (and the Cache Storage API in general). HTTP 30x redirects are followed automatically by default, and you should only have to route the original, non-redirected URL.
Here's a live example of a Glitch project that uses Workbox to cache that MP3 file: https://glitch.com/edit/#!/horn-sausage?path=sw.js:9:0
The relevant snippet of code, that also accounts for the fact that there is no CORS used when serving the files (so you'll get back an opaque response with a status of 0) is:
workbox.routing.registerRoute(
new RegExp('https://drive.google.com/'),
new workbox.strategies.CacheFirst({
plugins: [
new workbox.cacheableResponse.Plugin({statuses: [0, 200]})
],
})
);

Express JS - Want to cache static resources but NOT rendered HTML

I'm working on a dynamic application where we don't want to cache HTML (i.e. cart contents can change from one page refresh to the next). To that end, I'm calling middleware that sets cache-control headers to avoid caching. However, said cache-control headers also apply when fetching static resources. For obvious performance reasons, this is undesired behavior. We def want to cache static resources. My question is this... Is there a way to set diff response headers for static resources vs rendered html? I tried passing the setHeaders option to the express.static middleware, but the thread hangs, presumably because we are trying to set the same response header twice. Any help is greatly appreciated!
Edit: adding environment information -
I'm on Express 4 and Node 4.4
Edit: adding example code. This is the relevant bit from app.js that aggressively avoids caching HTML in browser.
app.use(express.static(config.static.public));
// ...Stuff
app.use(function (req, res, next) {
// Don't cache html
res.set('Cache-Control', 'no-cache, private, no-store, must-revalidate, '
+ 'max-stale=0, post-check=0, pre-check=0');
res.set('Expires', 'Fri, 31 Dec 1998 12:00:00 GMT');
next();
});
app.use(express.static("static", {maxage : 0}))
more info
Maybe clear all ready cached files in the browser before testing.

Force browser to query server for file even if it's cached, and prevent use of bfcache

Firefox on my PC ended up caching my Node.js server scripts extremely hard (Ctrl+F5 ignored) after I started sending this header:
resp.writeHead(code, {
"Content-Type": mime.lookup(path),
"Content-Length": stats.size,
"Cache-Control": "public, max-age=3672000",
// Write file last modified header
"Last-Modified": stats.mtime.toUTCString()
});
The problem is that the browser caches files in back-forward (BFCache) cache instead of HTTP cache and even after about a week (during which I debugged in Google Chrome instead) still remembers them and does not revalidate. I'd like to make browser remember the Last-Modified timestamp, always send request to server and my server will decide whether to send the file or 304 - Not modified header.
Apparently this problem is somehow related to Require.js, the issue only affects javascript files loaded by that framework.

Does express.static() cache files in the memory?

In ExpressJS for NodeJS, we can do the following:
app.use(express.static(__dirname + '/public'));
to serve all the static CSS, JS, and image files. My questions are these:
1) When we do that, does Express automatically cache the files in the server's memory or does it read from the hard disk every time one of the resources is served?
2) When we do that, does Express, using ETag by default, save the resources on the client's hard disk, or on the client's memory only?
The static middleware does no server-side caching. It lets you do two methods of client-side caching: ETag and Max-Age:
If the browser sees the ETag with the page, it will cache it. The next time the browser loads the page it checks for the ETag number changes. If the file is exactly the same, and so is its ETag - the server responds with an HTTP 304("not modified") status code instead of sending all the bytes again and saves a bunch of bandwidth.
Etag is turned-on by default but you can turn it off like this:
app.use(express.static(myStaticPath, {
etag: false
}))
Max-age is will set the max-age to some amount of time so the browser will only request that resource after one day has passed.
app.use(express.static(myStaticPath, {
maxAge: '5000' // uses milliseconds per docs
}))
For more details you can read this article
By default it's on the hard-drive, but someone can use something like this

Resources