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

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.

Related

SailsJs: getting "304 not modified" page after deploy

I'm trying to update my SailsJs application to fix the blank page wich I'm geting on Heroku, but I'm getting the status 304 not modified from browser.
I think I did everything I need to fix the blank page on my app, but I dont know why the page is not updating on Heroku
My Procfile:
web: node app.js
I appreciate if anyone can help.
Thanks!
I don't think that you need to fix anything. If you try to call the same url using POSTMAN or different browser you should get status 200.
You can add this to a policy instead and then just apply it to the specific pages/requests you want - if you do not want to set this for the entire application.
/api/policies/nocache.js:
/**
* Sets no-cache header in response.
*/
module.exports = function (req, res, next) {
sails.log.info("Applying disable cache policy");
res.header('Cache-Control', 'private, no-cache, no-store, must-revalidate');
res.header('Expires', '-1');
res.header('Pragma', 'no-cache');
next();
};
Don't forget to include nocatche into config/policy.js
'*': 'nocatche'

Prevent Getting Json Response from Cache in Express JS

I'm using Express and Node to build a web, where the client uses RESTful API to get Json response to show a list of objects.
After creating a new object, the app should request a new json response of the updated object list. Chrome works fine - new json response returned with status code 200 OK. However, things are not good in IE and Edge - it seems the browser just fetch the json response from cache (with status code 304), instead of making a new request. If I manually clear the browser cache data things will be fine.
I tried this solution: using a middleware to set max-age of cache-control res.header to be 0
function headerSet(req, res, next) {
res.header('Cache-Control', 'public, max-age=0');
return next();
}
And in the response header I can see accordant settings taking effect, however, IE and Edge still refuse to make a new request - I'm still getting the unupdated json response with 304.
What possibly have I done wrong?
Instead of setting max age try with the following.
res.header('Cache-Control', 'private, no-cache, no-store, must-revalidate');

How to make browser cache assets with express.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?

Configure sails.js not to cache the response

I have an application on node.js using sails.js as a framework. For displaying the informations to the user I have implemented some .ejs files.
When navigating using links within the app menu, I receive a "304 - Nod Modified" response. Also, within headers in the response I see Etag, If-None-Match or Expires.
After reading some posts, I have added the "app.disable('etag')" statement within /config/express.js file in the customMiddleware function and etag and if-none-match are not sent anymore.
Anyway, now I do not see any request made to the server (just the first one is made) when accessing different pages (not even 304 response).
How can I tell sails.js to stop caching my pages?
You can add this to a policy instead and then just apply it to the specific pages/requests you want - if you do not want to set this for the entire application.
/api/policies/nocache.js:
/**
* Sets no-cache header in response.
*/
module.exports = function (req, res, next) {
sails.log.info("Applying disable cache policy");
res.header('Cache-Control', 'private, no-cache, no-store, must-revalidate');
res.header('Expires', '-1');
res.header('Pragma', 'no-cache');
next();
};
It seems that adding the code below solved my problem:
res.header('Cache-Control', 'private, no-cache, no-store, must-revalidate');
res.header('Expires', '-1');
res.header('Pragma', 'no-cache');
These line should be included in the customMiddleware function from the /config/express.js file.
If there is a cleaner way to achieve the same result, please reply.

NodeJS/express: Cache and 304 status code

When I reload a website made with express, I get a blank page with Safari (not with Chrome) because the NodeJS server sends me a 304 status code.
How to solve this?
Of course, this could also be just a problem of Safari, but actually it works on all other websites fine, so it has to be a problem on my NodeJS server, too.
To generate the pages, I'm using Jade with res.render.
Update: It seems like this problem occurs because Safari sends 'cache-control': 'max-age=0' on reload.
Update 2: I now have a workaround, but is there a better solution?
Workaround:
app.get('/:language(' + content.languageSelector + ')/:page', function (req, res)
{
// Disable caching for content files
res.header("Cache-Control", "no-cache, no-store, must-revalidate");
res.header("Pragma", "no-cache");
res.header("Expires", 0);
// rendering stuff hereā€¦
}
Update 3:
So the complete code part is currently:
app.get('/:language(' + content.languageSelector + ')/:page', pageHandle);
function pageHandle (req, res)
{
var language = req.params.language;
var thisPage = content.getPage(req.params.page, language);
if (thisPage)
{
// Disable caching for content files
res.header("Cache-Control", "no-cache, no-store, must-revalidate");
res.header("Pragma", "no-cache");
res.header("Expires", 0);
res.render(thisPage.file + '_' + language, {
thisPage : thisPage,
language: language,
languages: content.languages,
navigation: content.navigation,
footerNavigation: content.footerNavigation,
currentYear: new Date().getFullYear()
});
}
else
{
error404Handling(req, res);
}
}
Easiest solution:
app.disable('etag');
Alternate solution here if you want more control:
http://vlasenko.org/2011/10/12/expressconnect-static-set-last-modified-to-now-to-avoid-304-not-modified/
Try using private browsing in Safari or deleting your entire cache/cookies.
I've had some similar issues using chrome when the browser thought it had the website in its cache but actually had not.
The part of the http request that makes the server respond a 304 is the etag. Seems like Safari is sending the right etag without having the corresponding cache.
I had the same problem in Safari and Chrome (the only ones I've tested) but I just did something that seems to work, at least I haven't been able to reproduce the problem since I added the solution. What I did was add a metatag to the header with a generated timstamp. Doesn't seem right but it's simple :)
<meta name="304workaround" content="2013-10-24 21:17:23">
Update
P.S
As far as I can tell, the problem disappears when I remove my node proxy (by proxy i mean both express.vhost and http-proxy module), which is weird...
As you said, Safari sends Cache-Control: max-age=0 on reload. Express (or more specifically, Express's dependency, node-fresh) considers the cache stale when Cache-Control: no-cache headers are received, but it doesn't do the same for Cache-Control: max-age=0. From what I can tell, it probably should. But I'm not an expert on caching.
The fix is to change (what is currently) line 37 of node-fresh/index.js from
if (cc && cc.indexOf('no-cache') !== -1) return false;
to
if (cc && (cc.indexOf('no-cache') !== -1 ||
cc.indexOf('max-age=0') !== -1)) return false;
I forked node-fresh and express to include this fix in my project's package.json via npm, you could do the same. Here are my forks, for example:
https://github.com/stratusdata/node-fresh
https://github.com/stratusdata/express#safari-reload-fix
The safari-reload-fix branch is based on the 3.4.7 tag.
Old question, I know. Disabling the cache facility is not needed and not the best way to manage the problem. By disabling the cache facility the server needs to work harder and generates more traffic. Also the browser and device needs to work harder, especially on mobile devices this could be a problem.
The empty page can be easily solved by using Shift key+reload button at the browser.
The empty page can be a result of:
a bug in your code
while testing you served an empty page (you can't
remember) that is cached by the browser
a bug in Safari (if so,
please report it to Apple and don't try to fix it yourself)
Try first the Shift keyboard key + reload button and see if the problem still exists and review your code.
Operating system: Windows
Browser: Chrome
I used Ctrl + F5 keyboard combination. By doing so, instead of reading from cache, I wanted to get a new response. The solution is to do hard refresh the page.
On MDN Web Docs:
"The HTTP 304 Not Modified client redirection response code indicates
that there is no need to retransmit the requested resources. It is an
implicit redirection to a cached resource."
// just add * in URL
app.get('/api*', (req, res)=>{
// do something
});

Resources