I want to serve user-specific static content in Express. That means, if a user is logged in, his private static folder is served by express. Other users shall not have access.
I tried the following (see below), but the static content is not being served. In fact, the route seems to be completely ignored and I get a 404.
I am not sure if the way I do it is the right way to go and if express is capable of dynamically serving different static folders. Thanks in advance for your thoughts on this.
Here's the code (simplified):
routes.js:
express = require 'express'
router = express.Router()
router.use '/user/assets', (req, res, next) ->
if req.user
userpath = 'uploads/' + md5(req.user._id)
if not fs.existsSync userpath
fs.mkdirSync userpath
console.log "Created user directory at " + userpath
express.static(userpath)
next()
module.exports = router
index.js:
express = require 'express'
app = express()
app.use '/', require './routes'
Sidenotes:
The md5 is just a way of escaping weird characters in the user id, which is a string. I know there is a possibility for a mismatch, which is tiny, and about which I don't wanna care for now. Concerns about general security of the fashion of the solving attempt are appreciated.
The code is written in CoffeeScript.
req.user contains a valid user element.
Just calling express.static is not enough, you need to use() it with the router. Unfortunately you can't directly do that, since you require a different set of routes for each user.
Calling express.static will return a middleware function. You could call it directly, i.e. something like this:
var files = express.static(userpath);
return files(req, res, next);
However that's still not enough, as the middleware uses req.url to build the file path. The express router adjusts this property and removes the mount point (see req.originalUrl in the docs). So you need to strip /user/assets from it, before calling the middleware.
By the way, you should set the DEBUG environment variable for node. It allows you to see what routes are created by express, which is very handy in debugging express.static 404 problems. E.g. you'd do $ DEBUG=* node index.js on Linux.
As you can see the approach starts to be a bit hacky and creating a new express.static middleware on each request is not very performance friendly too. So depending on what your user directories contain, using res.sendFile might actually be better.
As a sidenote, I assume you've checked that req.user actually contains something if the user is logged in.
Related
I was learning NodeJs advance concepts after going through the basic course.
I am following stepehen grinder course where we would be using his folliwng repo
I was initially walking through the repo where somethings were sort of new to me
My main question evolves around his index.js file in repo
This isn't prime question but first he have done something like this
require('./routes/authRoutes')(app);
require('./routes/blogRoutes')(app);
Is this equivalent to something like this
const auth = require('./routes/auth.js')
const profile = require("./routes/profile.js")
app.use('/auth', auth)
app.use('/profile', profile)
Second, Primary question, In his index.js file he have done something like this
if (['production'].includes(process.env.NODE_ENV)) {
app.use(express.static('client/build'));
const path = require('path');
app.get('*', (req, res) => {
res.sendFile(path.resolve('client', 'build', 'index.html'));
});
}
This does not make sense to me at all, can someone explain me what does the above code do? and an interesting article which can help me comprehend.
Also, Can someone please tell me what does path module do? I went through their do documentation and was able to comprehend that path allows us to access files outside our node project. Is that correct understanding?
Concerning you first question:
It's not the same. app.use(...) defines a middleware that gets executed on all and every routes. Here, both routes files export a function which takes one argument: the application (ExpressJS server) instance.
So, require('./routes/blogRoutes') gives you a function app => {...}, and by adding parenthesis and the app variable as a parameter you immediately execute this function with the current server (application) instance. Which in the end will create all the routes defined in the route file.
Concerning your second question:
The if is testing if the NODE_ENV variable is equal to production. If it is in production mode, app.use(express.static('client/build')); tells ExpressJS to serve static files from the client/build folder.
The rest of the code app.get('*', ...) send the index.html file for calls made to any route except the one defined in the two routes files.
The path.resolve only role is to easily build the absolute path of the index.html file.
Hi I need some help with how express handles routes.
In setting up my express app, I have something like this:
app.use(express.static('public'));
Next, I mount some api routes:
app.use('/api', myrouter);
app.get('*', function(req, res) {
res.sendFile(path.resolve('public/index.html'));
});
But, when the frontend requests data via an api route, e.g. at 'localhost:3000/api/things', I am seeing in the Express debug logs that at some point (unsure when) it actually tries to serve this request as a static file, like:
send stat "C:\myproject\public\api\things" +230ms
Even though this folder doesn't exist in 'public' and should be solely handled by my api. FYI, the handler for /api/things route is only implemented for the GET method, and does get invoked at some point.
How do I stop express server from also trying to serve api requests from the static folder?
Thanks very much.
Answering my own question... which appears to be a duplicate of this one:
`express.static()` keeps routing my files from the route
So the answer is this one: https://stackoverflow.com/a/28143812/8670745
In short, the app.use() declarations that mount your api routers should appear before the app.use() statements which tell express.static where to serve your static files from. This way, the latter acts as a catchall AFTER api route handling is done. Router engine order matters...
Your answer is misinformed, or rather you've misinterpreted the problem. Your original configuration:
app.use(express.static(__dirname + 'public'));
app.use('/api', myrouter);
Looks absolutely fine because there's no clash between the routes. The threads you've linked too aren't really the same, and I can see why moving the routes in those cases would have worked.
The only thing I'd say is your path to your static folder isn't reliable, you should really use path.join, or actually in your case you can just do express.static('public') - express will infer the folder your app is served from.
There currently is a difference between
app.use(function(req,res,next){
});
and
router.use('/some_route', function(req,res,next){
});
...The difference being that app.use runs for every request and router.use only runs for matching routes.
My question is about the router that must lie underneath app. Surely app has some default router internal to it. Is there a way to access that router...app.router? I thought that was deprecated?
Secondly, what I am really looking for is a way to access the current router being used.
For example,
app.use(function(req,res,next){
var currentRouter = req.app._router // (?)
});
or
router.use(function(req,res,next){
var currentRouter = req._router //(?)
});
where req._router would be equal to the same router for the router.use call of course.
In the latest Express code, the default app router is in app._router.
It is created lazily which means it's not created until a route is actually defined (with app.use() or app.get() or something like that).
It does not appear that this is meant to be a public property and thus is subject to change. You can, of course, just define your own router with the root path and only use your own router and then you would not have to access or use this non-public property.
You are correct that app.router is deprecated. Trying to access it purposely throws an exception in the Express code.
I was just reading the documentation on express and found these two terms, app.use(); and router.use();
I know app.use(); is used in node for Mounting a middleware at a path, and we often use it in most of the node apps. but what is router.use(); are they both same? if not, whats the difference ?
I read about router here. I also found similar questions on SO What is the difference between "express.Router" and routing using "app.get"?
and Difference between app.all('*') and app.use('/'), but they do not really answer my question. Thanks.
router.get is only for defining subpaths. Consider this example:
var router = express.Router();
app.use('/first', router); // Mount the router as middleware at path /first
router.get('/sud', smaller);
router.get('/user', bigger);
If you open /first/sud, then the smaller function will get called.
If you open /first/user, then the bigger function will get called.
In short, app.use('/first', router) mounts the middleware at path /first, then router.get sets the subpath accordingly.
But if we instead use the following:
app.use('/first', fun);
app.get('/sud', bigger);
app.get('/user', smaller);
If you open /first in your browser, fun will get called,
For /sud, bigger will get called
For /user, smaller will get called
But remember for /first/sud, no function will get called.
This link may also help: http://expressjs.com/api.html#router
router.use(); mounts middleware for the routes served by the specific router, app.use(); mounts middleware for all routes of the app (or those matching the routes specified if you use app.use('/ANYROUTESHERE', yourMiddleware());).
Example use case could be an app with one router with standard routes and one router that handles api routes, which need a valid user.
You would then mount the authentication middleware for the api router only with router.use(yourAuthMiddleware());.
If you would have an app though that requires a valid user for all routes, mount the middleware for the app with app.use(yourAuthMiddleware());
app.use() used to Mounts the middleware function or functions at the specified path,the middleware function is executed when the base of the requested path matches path.
router.use() is used to middleware function or functions, The defaults mount path to “/”.
But in
app.use() you will have to give a specified path like that:
var adsRouter = require('./adsRouter.js');
app.use('/ads', adsRouter);
or
app.use('/ads', function(req, res, next) {
// write your callback code here.
});
But while using router.use() you can give only middleware, like this:
router.use(function(req, res, next) {
console.log('%s %s %s', req.method, req.url, req.path);
next();
});
or
router.use('/test', function(req, res, next) {
// write your callback code here.
next();
});
or
//in router.js
router.use('/admin', authUtil.verifySessionId, authUtil.verifyLisencee);
router.post('/admin', controllerIndex.ads.adListingAdmin);
In the above code when the end point is '/admin' then first it will call the authUtil.verifySessionId and authUtil.verifyLisencee then it will execute next line with 'admin' end point and according to controllerIndex.ads.adListingAdmin method.
app.use(middleware): application-level middleware.
router.use(middleware): router-level middleware.
("middleware" refers to methods/functions/operations that are called between processing the request and sending the response.)
See https://expressjs.com/en/guide/using-middleware.html for a comparison of different types of middleware used in an Express app.
When looking at the express js docs for Routing (https://expressjs.com/en/guide/routing.html#express-router):
Use the express.Router class to create modular, mountable route handlers. A Router instance is a complete middleware and routing system; for this reason, it is often referred to as a “mini-app”.
A Router created with express.Router() is no different than an app created with express() in terms of functionality; it's like a logical grouping of routes/handlers/services/databases/etc. The biggest difference is the scope that it affects. A router just affects its own scope while the app is like the master/global scope for your web/app server. You could have many routers or "apps" running on one main app/web server instance. This is why you could listen to requests on an app instance via app.listen(80) but not on a router.
Before I ask about app.router I think I should explain at least what I think happens when working with middleware. To use middleware, the function to use is app.use(). When the middleware is being executed, it will either call the next middleware by using next() or make it so no more middleware get called. That means that the order in which I place my middleware calls is important, because some middleware depends on other middleware, and some middleware near the end might not even be called.
Today I was working on my application and had my server running in the background. I wanted to make some changes and refresh my page and see the changes immediately. Specifically, I was making changes to my layout. I couldn't get it to work so I searched Stack Overflow for the answer and found this question. It says to make sure that express.static() is beneath require('stylus'). But when I was looking at that OP's code, I saw that he had his app.router call at the very end of his middleware calls, and I tried to figure out why that was.
When I made my Express.js application (version 3.0.0rc4), I used the command express app --sessions --css stylus and in my app.js file the code came setup with my app.router above both the express.static() and require('stylus') calls. So it seems like, if it comes already setup that way, then it should stay that way.
After re-arranging my code so I could see my Stylus changes, it looks like this:
app.configure(function(){
//app.set() calls
//app.use() calls
//...
app.use(app.router);
app.use(require('stylus').middleware(__dirname + '/public'));
app.use(express.static(__dirname + '/public', {maxAge: 31557600000}));
});
app.get('/', routes.index);
app.get('/test', function(req, res){
res.send('Test');
});
So I decided that the first step would be to find out why it is important to even have app.router in my code. So I commented it out, started my app and navigated to /. It displayed my index page just fine. Hmm, maybe it worked because I was exporting the routing from my routes file (routes.index). So next I navigated to /test and it displayed Test on the screen. Haha, OK, I have no idea what app.router does. Whether it is included in my code or not, my routing is fine. So I am definitely missing something.
So Here Is My Question:
Could somebody please explain what app.router does, the importance of it, and where I should place it in my middleware calls? It would also be nice if I got a brief explanation about express.static(). As far as I can tell, express.static() is a cache of my information, and if the application can't find the requested page, it will check the cache to see if it exists.
Note: This describes how Express worked in versions 2 and 3. See the end of this post for information about Express 4.
static simply serves files (static resources) from disk. You give it a path (sometimes called the mount point), and it serves the files in that folder.
For example, express.static('/var/www') would serve the files in that folder. So a request to your Node server for http://server/file.html would serve /var/www/file.html.
router is code that runs your routes. When you do app.get('/user', function(req, res) { ... });, it is the router that actually invokes the callback function to process the request.
The order that you pass things to app.use determines the order in which each middleware is given the opportunity to process a request. For example, if you have a file called test.html in your static folder and a route:
app.get('/test.html', function(req, res) {
res.send('Hello from route handler');
});
Which one gets sent to a client requesting http://server/test.html? Whichever middleware is given to use first.
If you do this:
app.use(express.static(__dirname + '/public'));
app.use(app.router);
Then the file on disk is served.
If you do it the other way,
app.use(app.router);
app.use(express.static(__dirname + '/public'));
Then the route handler gets the request, and "Hello from route handler" gets sent to the browser.
Usually, you want to put the router above the static middleware so that a accidentally-named file can't override one of your routes.
Note that if you don't explicitly use the router, it is implicitly added by Express at the point you define a route (which is why your routes still worked even though you commented out app.use(app.router)).
A commenter has brought up another point about the order of static and router that I hadn't addressed: the impact on your app's overall performance.
Another reason to use router above static is to optimize performance. If you put static first, then you'll hit the hard drive on every single request to see whether or not a file exists. In a quick test, I found that this overhead amounted to ~1ms on an unloaded server. (That number is much likely to be higher under load, where requests will compete for disk access.)
With router first, a request matching a route never has to hit the disk, saving precious milliseconds.
Of course, there are ways to mitigate static's overhead.
The best option is to put all of your static resources under a specific folder. (IE /static) You can then mount static to that path so that it only runs when the path starts with /static:
app.use('/static', express.static(__dirname + '/static'));
In this situation, you'd put this above router. This avoids processing other middleware/the router if a file is present, but to be honest, I doubt you'll gain that much.
You could also use staticCache, which caches static resources in-memory so that you don't have to hit the disk for commonly requested files. (Warning: staticCache will apparently be removed in the future.)
However, I don't think staticCache caches negative answers (when a file does not exist), so it doesn't help if you've put staticCache above router without mounting it to a path.
As with all questions about performance, measure and benchmark your real-world app (under load) to see where the bottlenecks really are.
Express 4
Express 4.0 removes app.router. All middleware (app.use) and routes (app.get et al) are now processed in precisely the order in which they are added.
In other words:
All routing methods will be added in the order in which they appear. You should not do app.use(app.router). This eliminates the most common issue with Express.
In other words, mixing app.use() and app[VERB]() will work exactly in the order in which they are called.
app.get('/', home);
app.use('/public', require('st')(process.cwd()));
app.get('/users', users.list);
app.post('/users', users.create);
Read more about changes in Express 4.
Routing means determining how an application responds to a client request to a particular endpoint, which is a URI (or path) and a specific HTTP request method (GET, POST, and so on).
Each route can have one or more handler functions, which are executed when the route is matched.
In Express 4.0 Router, we are given more flexibility than ever before in defining our routes.
express.Router() is use multiple times to define groups of routes.
route used as middleware to process requests.
route used as middleware to validate parameters using ".param()".
app.route() used as a shortcut to the Router to define multiple requests on a route
when we are using app.route(), we are attaching our app with that router.
var express = require('express'); //used as middleware
var app = express(); //instance of express.
app.use(app.router);
app.use(express.static(__dirname + '/public')); //All Static like [css,js,images] files are coming from public folder
app.set('views',__dirname + '/views'); //To set Views
app.set('view engine', 'ejs'); //sets View-Engine as ejs
app.engine('html', require('ejs').renderFile); //actually rendering HTML files through EJS.
app.get('/', function (req, res) {
res.render('index');
})
app.get('/test', function (req, res) {
res.send('test')
})
In express Version 4 we can easily define routes in the following manner:
server.js:
const express = require('express');
const app = express();
const route = require('./route');
app.use('/route', route);
// here we pass in the imported route object
app.listen(3000, () => console.log('Example app listening on port 3000!'));
route.js:
const express = require('express');
const router = express.Router();
router.get('/specialRoute', function (req, res, next) {
// route is now http://localhost:3000/route/specialRoute
});
router.get('/', function (req, res, next) {
// route is now http://localhost:3000/route
});
module.exports = router;
In server.js we imported the router object of the route.js file and apply it in the following manner in server.js:
app.use('/route', route);
Now all of the routes in the route.js have the following base URL:
http://localhost:3000/route
Why this approach:
The main advantage of taking this approach is that now our app is more modular. All the route handlers for a certain route now can be put into different files which makes everything more maintainable and easier to find.
An article by #kelyvinn from 2016, with the intent to demonstrate modularity, includes this code:
// controllers/apis/dogs/index.js
const
express = require('express'),
dogService = require('../../../services/dogs');
let router = express.Router();
router.get('/', dogService.getDogs);
router.get('/:id', dogService.getDogWithId);
module.exports = router;