nodeJs/Express dealing with missing static files - node.js

I have a node App. That is configured to serve static files by:
app.use(express.static(path.join(__dirname, '../public')));
And I use some auth middlewares on other routes. The problem comes up when I hit an image that doesn't exist on the server. In this case looks like express is trying to send that request through all of the middlewares that I have for NON-static content.
Is there a way to just send 404 for missing static asset, rather than re-trigger all middlewares per missing file?

The way that the express.static() middleware works by default is that it looks for the file in the target directory and if it is not found, then it passes it on to the next middleware.
But, it has a fallthrough option that if you set it to false, then it will immediately 404 any missing file that was supposed to be in the static directory.
From the express.static() doc:
fallthrough
When this option is true, client errors such as a bad request or a
request to a non-existent file will cause this middleware to simply
call next() to invoke the next middleware in the stack. When false,
these errors (even 404s), will invoke next(err).
Set this option to true so you can map multiple physical directories
to the same web address or for routes to fill in non-existent files.
Use false if you have mounted this middleware at a path designed to be
strictly a single file system directory, which allows for
short-circuiting 404s for less overhead. This middleware will also
reply to all methods.
Example:
app.use("/public", express.static("/static", {fallthrough: false}));

Related

I don't understand the logic of express.static(path.join(__dirname, 'public')))

I use this line
express.static(path.join(__dirname, 'public')));
Does it pass to the client post or get request?
Because if i use
express.get("/",function(res,req){
res.send(dataWirhDb);
}
There is no data on the client. If I use post request, I get data from the server.
If I use without
express.static(path.join(__dirname, 'public')))
and send to the client using get request, data is received on the client.
why does this happen?
No, express.static does not execute any requests. It's just a setup function that tells express that it needs to serve static files, and where to find them.
In this case the location is path.join(__dirname, 'public') , which means the public folder within your application directory.
The static files (like css, images, index.html etc.) are served automatically without the need of setting up routes for them. "Served" in this context means that the server sends the file back as a response to a GET request by the client, asking for that file.

How to prevent express server from serving api routes from the static folder

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.

Express middleware refrain static from going into next

I have the following function:
app.use('/Framework', express.static(path.resolve(__dirname, 'Framework')));
app.get('/*/*', function (req, res, next) {
...code...
);
The request goes into both the app.use and the app.get. I'd like it that when I try to access a resource with /Framework it just gives it to me as static while ignoring the other functions from below. Yet when accessing static it seems to go in the app.get.
Why is this happening and how can I modify it to get the wanted behavior?
Edit due to comment
I also have a
app.use('/Public', express.static(path.resolve(__dirname, 'Public')));
before which works perfectly as expected.
Requests such as : /Public/0.png work while requests such as /Framework/0.png enter both functions. I have checked the folders names over and over again and they are correct.
Express-static is Express middleware. Middleware is chained together and after a middleware is done executing its code, it calls next(); internally to allow the next middleware to execute. After all middleware is executed, the routes will be executed.
Since express-static calls next(); after its done, the routes will be invoked and checked if any routes match the request. Since your request /Public/0.png matches your route /*/* the route is executed.
My suggestion would be to try an rename your route from /*/* to something more specific.
You could try regex for the route which would explicitly allow any requests matching /*/* but would refuse any routes which have a file extension appended to it (i.e. /*/*.png).
Another (hacky) way would be to check for headersSent inside your /*/* route before executing the code within that route.
A side-note:
Seeing how your route name (e.g. Public and Framework) are the same as your directory names, you could simply do
app.use('/', express.static(path.resolve(__dirname, PARENT_DIRECTORY)));
Where PARENT_DIRECTORY is the parent directory of both Public and Framework. This way
Your directory structure would look like this:
Directory
|
| ---- Public
| ---- Framework
And any requests to Public would end up serving files from your Public directory, same for the Framework directory respectively.

What is the purpose on the middleware Yeoman function implementation?

I'm new in grunt-contrib-connect and came across with this follow middleware function Yoeman implementation -
middleware: function(connect, options, middlewares) {
return [
proxySnippet,
connect.static('.tmp'),
connect().use('/bower_components', connect.static('./bower_components')),
connect.static(config.app)
];
}
What is the purpose of this implementation ?
These are connect middlewares. A middleware is a request callback function which may be executed on each request. It can either modify/end the curent request-response cycle or pass the request to the next middleware in the stack. You can learn more about middlewares from express guide.
In your code you have four middlewares in the stack. First one is for proxying current request to another server. And rest three middlewares are for serving static files from three different directories.
When a request is made to the server, it'll go through these middlewares in following order:
Check if the request should be proxied. If it is proxied to other server, then it's the end of the request/response cycle, rest three middlewares will be ignored.
If not proxied, it'll try to serve the requested file from ./tmp directory.
If the file isn't found in above, it'll look inside ./bower_components. Note that this middleware will be executed only for the requests that has `/bower_components/ in the path. e.g. http://localhost:9000/bower_components/bootstrap/bootstrap.js
Finally, if file isn't found in above two directories, it'll look for it in whatever the path is set in config.app.
That's the end of stack, after that you'll get a 404 Not found error.

How to use static folder but also use routing in Express?

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.

Resources