Reputation: 5370
By default, my browser caches webpages of my ExpressJS app.
This is causing a problem to my login system (users not logged in can open old cached pages of logged in users).
How do I disable this caching?
EDIT:
My app.js
(main file):
var express = require('express');
var http = require('http');
var path = require('path');
var store = require('./routes/store');
var app = express();
app.configure(function(){
app.set('port', process.env.PORT || 3012);
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.cookieParser('your secret here'));
app.use(express.session());
app.use(app.router);
app.use(require('stylus').middleware(__dirname + '/public'));
app.use(express.static(path.join(__dirname, 'public')));
});
app.configure('development', function(){
app.use(express.errorHandler());
});
app.get('/', store.home);
app.post('/', store.home);
app.get('/addProblem', store.addProblem);
app.post('/addProblem', store.addProblem);
app.get('/problem', store.problem);
app.post('/problem', store.problem);
app.get('/problemList', store.problemList);
app.post('/problemList', store.problemList);
app.get('/main', store.main);
app.post('/main', store.main);
app.post('/login', store.login);
app.get('/login', store.login);
app.get('/createProblem', store.createProblem);
app.post('/createProblem', store.createProblem);
app.post('/register', store.register);
app.get('/register', store.register);
app.post('/evaluate', store.evaluate);
app.get('/evaluate', store.evaluate);
app.get('/logout', store.logout);
app.post('/logout', store.logout);
http.createServer(app).listen(app.get('port'), function(){
console.log("Express server listening on port " + app.get('port'));
});
Upvotes: 41
Views: 67845
Reputation: 16294
Don't waste your time reinventing the wheel, use the nocache middleware instead. It has been here for 9 years (2024) and it is downloaded more than 2 million times per week. Having only 140 stars on github, this is actually one of those unsung heroes of the express ecosystem.
npm install --save nocache
const nocache = require('nocache');
app.use(nocache());
When installed as a middleware it sets four headers, disabling a lot of browser caching. This is the complete list of the updated headers.
- Cache-Control: no-store, no-cache, must-revalidate, proxy-revalidate
- Pragma: no-cache
- Expires: 0
- Surrogate-Control: no-store
Even if you are using nocache
, the ETag header isn't removed, because it works in a different way. It's generated at the end of the request and could be another source of unintended caching. In order to handle it you have two choices.
The first is disabling it using express builtin app.set('etag', false);
method.
The second is removing the header just before it is sent to the client using the on-headers module:
const onHeaders = require('on-headers');
// install it as a middleware
app.use((req, res, next) => {
// listen for the headers event
onHeaders(res, () => {
this.removeHeader('ETag');
});
});
As pointed out in the comments this is actually a "ten-liner" package but it belongs to the Helmet project, a long running initiative to secure Express applications. Before downvoting this answer take a look at the project and remember that if you are looking for an answer, maybe you don't really know Express or HTTP. In this case it is better to use an already made package, especially a trusted one like that.
Upvotes: 44
Reputation: 19
You can create a middleware, set headers in it so that there is no caching, and use in those route handlers that require authorization.
middleware cookies:
const cookie = async (req, res, next) => {
try {
const token = req.cookies.token;
const check = jwt.verify(token, process.env.JWT_SECRET);
const user = await User.findOne({_id: check._id, 'tokens.token': token});
if (!user) {
throw new Error();
}
req.token = token;
req.user = user;
res.set({
"Cache-Control": "no-store, no-cache, must-revalidate, proxy-revalidate",
"Pragma": "no-cache",
"Expires": "0",
"Surrogate-Control": "no-store"
});
next();
} catch (e) {
res.set({
"Cache-Control": "no-store, no-cache, must-revalidate, proxy-revalidate",
"Pragma": "no-cache",
"Expires": "0",
"Surrogate-Control": "no-store"
}).redirect(301, '/login');
}
};
used:
router.get('/all/tasks', cookie, async (req, res) => {
try {
const task = await Task.find({owner: req.user._id});
if (!task) {
return res.status(404).send();
}
res.status(200).render('tasks', {
title: 'Your task',
task: task
});
} catch {
res.status(500).send();
}
});
Ps: I took the headers from the nocashe library https://www.npmjs.com/package/nocache
Upvotes: 1
Reputation: 5213
There are two things to consider when dealing with cache in Express.js - ETag
and Cache-Control
headers.
ETag (MDN reference)
If you have dynamic content which does not benefit from ETags, it's best to disable it because it incurs small overhead with each request.
app.set('etag', false)
Cache-Control (MDN reference)
To completely disable cache, use the following header:
app.use((req, res, next) => {
res.set('Cache-Control', 'no-store')
next()
})
This header does not affect express.static()
middleware. It handles cache in its own way.
Upvotes: 42