I'm a little confused as to how Express serves files.
Currently I have a /public directory to hold client-side resources. I configure Express using
app.use(express.static(__dirname + '/public'));
It was my impression that anything in this directory was public, and that HTTP method urls defaulted /public as the root directory for access (unless otherwise routed manually by Express).
There is no problem using GET on any file in this directory (client-side scripts, images, ect. However, I get 404's when trying to POST files inside this directory. Do I need to manually route all POST requests ala
app.post(route, callback)
Thanks for you help
Connect, and therefore, Express, the static middleware only accepts GET requests. See here.
If you are trying to overwrite files in the public with a POST, you'll want to create a separate route for that.
Connect/Express' static middleware only supports GET and HEAD method:
if ('GET' != req.method && 'HEAD' != req.method) return next();
So, yes, if you want to be able to POST to paths matching static files, you'll need to define the handler(s) yourself.
I find an easy way to post static
app.use(staticPath, function(req, res, next){
if ('POST' != req.method){
next()
}else{
req.method = 'GET'
next()
}
})
app.use(staticPath, express.static('./static'))
It works well, haha
Related
I'm building an application that has two separate parts to it, which on the frontend I am building as two separate Angular apps. I am doing it this way so that I can better divide control access to he codebase and not unnecessarily give some team members access to code they do not need.
So there are two separate applications, served from the same NodeJS server. The app that is served depends on whether the user is logged in. If they are a guest user, they get one version app, if they are registered user they get a privileged version of the app with more features.
How can I conditionally/dynamically serve static files in Express, so as to say, "if User1 is a guest, serve Application A, otherwise serve Application B"?
If it's just one file you're talking about serving (e.g. app-1.js or app-2.js) then you don't need express.static. You can just handle the request in a normal route handler with res.sendFile like so:
app.get('/get-app', function(req, res) {
if (userIsLoggedIn()) {
res.sendFile('/path-to-logged-in-app.js')
} else {
res.sendFile('/path-to-logged-out-app.js')
}
})
More about res.sendFile here.
If you want to serve multiple files via express.static, you'll need two instances of express.static middleware, and another piece of middleware on top of that to modify the request url depending up on the user's logged in status. Maybe something along the lines of the following:
// Middleware function to modify the request url based on user's status
function checkUser(req, res, next) {
if (userIsLoggedIn()) {
req.url = `/app-1/${req.url}`
} else {
req.url = `/app-2/${req.url}`
}
next()
}
// Set up the middleware stack
app.use(checkUser)
app.use('/app-1', express.static(path.join(__dirname, 'app-1')))
app.use('/app-2', express.static(path.join(__dirname, 'app-2')))
More about writing your own middleware here. You also might want to add some logic in checkUser to only prepend to urls requesting static files (e.g. request urls to /assets/foo.js get the prepend treatment but requests to /api/some-api-function do not).
All that said, I'm not that familiar with Angular but I'd suggest investigating other ways to serve logged in / logged out content. I'm assuming there is some concept of components or "views" in Angular, and it's probably a lot cleaner to just render a "LoggedIn" or "LoggedOut" component/view vs. sending a whole different "app".
I have a mobile app that loads images via http. I'm using a GET parameter for cache busting. In QA and Production the images are served via S3 and this works fine. But in development I'm serving them directly from my node / express backend with express.static(). But here the get parameter makes static not find the file. Is there a way to tell express.static to ignore GET parameter? I digged around code but could find anything obvious. Ideas?
+++UPDATE+++
Code and usage example:
//serve assets on the dev server only
if ((process.env.NODE_ENV || 'DEVELOPMENT') == 'DEVELOPMENT') {
app.use(express.static(path.resolve(__dirname,'..','public')));
}
This one works:
localhost:3000/assets/avatars/example.png
This one doesn't:
localhost:3000/assets/avatars/example.png?v=2
+++CLOSED++++
The mistake actually, as suggested below, had nothing to do with static routing. Sincere apologies for wasting your time.
Express is running all the route you define one after another, so if you do:
app.use('/',express.static('/'))
app.get('/myparamter',function(req,res,next){
res.send('This Will never be called')
})
But if you do:
app.get('/myparamter',function(req,res,next){
res.send('This Will be called if you request /myparmeter')
})
// If not another route matches the URL it will server default static file.
app.use('/',express.static('/'))
I'm having a major issue with Routing in Express.
In my project, there is a folder /public.
Inside /folder I have some other folders like
- public
|- user
|- common
Initially, the only way pages were served by my Node.js server was through res.sendFile(../..). The problem was that the .js files and .css files did not know where to go.
So I added
app.use('/', express.static(__dirname + '/public'));
But now the problem is, if I try to visit /user what happens is, that the static version of the index.html file in that folder is returned, and my route defined in the node app is ignored!
This route - and most importantly the auth middleware is never touched!
How do I reconcile the need to serve files from a static folder, but also may have routes of the same name that I want to control more closely?
app.use('/user', userauth, userRoutes);
Assuming /user is some sort of API I don't think express.static was intended to be used that way. I think the best solution would be to use different routes. You could add something like /api/ to the beginning of all your routes or make sure your static files are organized under /css, /js, /partials, etc.
If you absolutely must support /user for static files AND your api calls you will need to ditch express.static and use something like the Accept header with custom middleware that determines what the browser is asking for. Depending on the scenario this may get complicated to support all the variables. A simple example would be something like this:
app.use(function(req, res, next){
// check Accept header to make sure its a JSON request
if(req.accepts('application/json') && !req.accepts('html')) {
// JSON request so forward request on to the next middleware(eventually hitting the route)
return next();
}
// NOT a JSON request so lets serve up the file if it exists...
// TODO use req.path to check if file exists - if not 404 - will also need to map paths
// to /users to check for /users/index.html if you need to support that
var fileExists = false;
return fileExists ? res.sendFile('...') || res.status(404).send('Not Found');
});
You would have to make sure when the client calls /users it sets the Accept header to application/json. Most client side frameworks have a way to do this for all AJAX requests.
I'm using PassportJS to secure a WebApp (written with AngularJS). I'm using NodeJS with Express (4.0.0) to serve static content after the login-screen. I don't get how to use a middleware along with express.static() at the same time.
My (not working) code looks like
app.use('/secure',
function (req, res, next) {
if (req.isAuthenticated())
return next();
res.redirect('/');
},
express.static(__dirname + '/../../client'));
The plan is, that the middleware ensures, that the user is only forwareded to the WebApp if he/she is logged in. If not, he/she/it is redirected to the root folder.
I found this answer, but according to the documentation, the new version supports multiple functions. This isn't the "clean" solution I'm looking for, since the directory contains too many subfolders and files.
Thanks in advance
When you attach middlewares to the same route they get executed in the same order of declaration, so if you want to execute any middleware before express.static, all what you have to do is attach it to the same route and declare it before.
app.use('/secure', myMiddleWare);
app.use('/secure', express.static(__dirname + '/../../client'));
I'm building a single page application using Express for the backend and AngularJS for the frontend and I'm having some cache problems.
I'm not using express views, only serving files with express.static middleware.
My static files are in public/app or public/dist depending on enviroment (dist has minified files).
app.use app.router
app.use express.static(cwd + '/public/' + publicFolder, maxAge: MAX_AGE)
When requesting '/', app.router verifies if user is logged in, and if everything is ok then index.html is served via express.static (I just call next() in the controller). If user is not logged in, it gets redirected to login.html
My problem is that if I set maxAge, my index.html file gets cached and the first request to '/' doesn't go through router. I can enter the app even if I'm not logged in.
If I set maxAge to 0, the problem goes away, but I want to cache all my *.js and *.css files.
What is the correct approach to this kind of problems? Start using views? Different express.static mount points?
You can always define individual routes without necessarily using views (although view templates aren't a bad idea). In this way you could define index.html just to apply the special case maxAge.
Just be sure to put the route before the static middleware.
If you wanted you could even use send, the same static server that the static middleware uses behind the scenes. Something like:
// install send from npm
var send = require("send");
app.get("/index.html", function (req, res) {
send(req, "/index.html")
.maxage(0)
.root(__dirname + "/public")
.pipe(res);
});
Or the more low level stream way, something like:
app.get("/index.html", function (req, res) {
res.setHeader('Content-Type', 'text/html');
res.setHeader('Cache-Control', 'public, max-age=0');
// Note that you'd probably want to stat the file for `content-length`
// as well. This is just an example.
var stream = fs.createReadStream(__dirname + '/public/index.html');
stream.pipe(res);
});