NodeJS Express wildcard route executed several times - node.js

Consider the following code snippet:
var count = 0;
function a(req, res, next){
count++;
console.log(count);
next();
};
app.get('*', a);
app.get("/", routes.index);
app.get("/foo", routes.foo);
Function a() will be executed for every route defined, in this case 2, per http request. The count variable is just to illustrate. So if I had 100 routes defined, a() would be executed 100 times per request to the site. Is this the expected behavior, or am I doing something wrong? Thanks!

You should check out the network traffic or log the request in your a function. Most likely the second request you are seeing is for favicon.ico. Each route when only be called once per matching request.

Related

what happens in app.use(express.static) and app.use(require("cors")()) and what middlewares are

I started with express a few days ago.
I dont really understand what happens in:
const express = require("express")
const app = express()
app.use(express.static(path.join(), "public"))
app.use(require("cors")())
app.listen(3000, () => console.log("running"))
the first example worked for me but i dont really understand it.
and basiclly i dont understand what happens in app.use() and what middlewares are..
someone can help me pls?
i read many blogs and I didnt got it :(
The Background
There are several parts to explaining this. First, off app.use() expects a middleware function to be passed to it. That would be a function with a signature like this:
app.use(function(req, res, next) {
console.log(req.path); // log incoming request path
next(); // continue routing to other handlers
});
It accepts other combinations of parameters, including an initial path and you can pass multiple middleware functions too and it will chain them together, but the basics of your question is about a single middleware function as shown above. That middleware function gets three arguments req - the incoming request object, res - the outgoing response objet and next - a function to call if you want to continue routing or report an error.
The job of one of these middleware function is to use the input in the req object to do some kind of processing of that input (depending upon what the purpose of the middleware function is) and then do one of three things:
Send a response using something like res.send() in which case the request has been handled and a response has been sent and no further routing will be done.
Continue routing to further request handlers in the chain by calling next().
Abort routing and go to the Express error handler by calling next(err).
The express.static() Middleware
So, that's what is expected of a function passed to app.use(). Now, let's look at the two examples you ask about. Let's start with express.static():
app.use(express.static(path.join(), "public"))
First, this isn't proper use of express.static(). I'm not sure exactly what you intended, but I will assume you meant something like this:
app.use(express.static(path.join(__dirname, "public")));
In this case, express.static() takes some configuration information which is the resulting path from calling path.join(__dirname, "public") and uses that to create a custom middleware function. So, calling express.static(path.join(__dirname, "public")) returns a function that expects to be called with the three middleware arguments we previously discussed. It is logically identical to this:
const publicPath = path.join(__dirname, "public");
const myStaticMiddleware = express.static(publicPath);
app.use(myStaticMiddleware);
which is logically equivalent to this:
const publicPath = path.join(__dirname, "public");
const myStaticMiddleware = express.static(publicPath);
app.use(function(req, res, next) {
myStaticMiddleware(req, res, next);
});
Where the code has been broken down into separate steps just so you can see each step separately.
And, in case you didn't already know, the point of the express.static() middleware is to serve static files from a designated directory if an incoming request matches a filename in that designated directory exactly and has an appropriate file type.
The cors Middleware
For your second example:
app.use(require("cors")())
Let's again break that down to the individual steps:
const cors = require("cors"); // load cors module
const corsMiddleware = cors(); // create cors middleware function
app.use(corsMiddleware); // register middleware with Express server
Which can be expanded to:
const cors = require("cors");
const corsMiddleware = cors();
app.use(function(req, res, next) {
corsMiddleware(req, res, next);
});
Just to show you that corsMiddleware is called with these three arguments.
The purpose of this particular middleware is to help configure a response to this request so that cross origin requests will be accepted.

node express - does middle way order matter? Getting error

My code below gives me an error: Error: Can't set headers after they are sent.
If I put app.use('/special/... before app.use('/' ... it doesn't give me an error-
1. As I understand when using app.use the order does matter because the program doesn't look like when I use app.get for example, for anything after '/ or '/special/ so why am I getting an error?
Also when I put app.use('/special/' first I am still not seeing "first" and second" but only the first one - even though I use next..
Can someone explain?
Thanks!!
What does it mean?
var express=require ('express');
var app=express();
app.use('/',function(req,res,next){
res.send('first');
next();
});
app.use('/special/',function(req,res,next){
res.send('second');
next();
});
app.listen(3000, function(){
console.log('Server listening');
});
In your case it's nothing about order, but you can't invoke res.send('some_result') twice when one resource required,you can check this in detail Stackoverflow.
also, when you use app.use() to add middleware to your system,Express use regex to match your request url,so when you have the code below:
app.use('/',function(req,res,next){
res.send('first');
next();
});
all the request(regardless of HTTP verb) start with '/' will meet the requirement.
finally when request below:
POST /special
both of the middlewares will be invoked.
Problem
The two routes
app.use('/',function(req,res,next){
res.send('first');
next();
});
app.use('/special/',function(req,res,next){
res.send('second');
next();
});
both match the url /special. That's why both of them are executed by node. Since res.send() in the first route closes the http response from the server, the res.send() in the second router throws an error since it tries to set a header (e. g. Content-length) while output from the first route has already been sent.
Solution
Always put the more specific route first so that it is reached at all. If the first route you define matches /, no other route would ever be called.
Also, do not call next() if you want to call res.send() in routes. Best practice: next() should only be invoked in middlewares which do not send a response.
A possible solution looks like this:
var express=require ('express');
var app=express();
app.use('/special/',function(req,res){
res.send('second');
});
app.use('/',function(req,res){
res.send('first');
});
app.listen(3000, function(){
console.log('Server listening');
});

How Express recorgonizes middlewares?

I'm novice in Express and a little bit confused about how it handles middlewares? So basically I have two middlewares which looks like:
app.use(require('_/app/middlewares/errors/404'))
app.use(require('_/app/middlewares/errors/500'))
404
var log = require('_/log')
module.exports = function (req, res, next) {
log.warn('page not found', req.url)
res.status(404).render('errors/404')
}
500
var log = require('_/log')
module.exports = function (er, req, res, next) {
log.error(er.message)
res.locals.error = er
res.status(500).render('errors/500')
}
So now I want to add my custom middleware app.use(require('_/app/middleware/shareLocals')) which looks like:
module.exports = function (req, res, next) {
res.locals.base_url = req.protocol + '://' + req.get('host');
next();
}
The main problem is that now when I try to use base_url I get 404 error...
So how Express understands what middleware do? That is between my middleware and 404 are no visual differences:
it receives same params
it doesn’t have any if's in it, just throws 404 error
Appears the feeling the middlewares in Express are made for errors (when excepts err as first param) and for 404 (when there is no first err)...
P.S.
Is there any difference defining middlewares before or after routes?
P.S. Is there any difference defining middlewares before or after routes?
Yes.
The order in which you register your middlewares (and routes) have a lot to say.
Image express as a giant list. Starting at the first element in the list, you have the first middleware OR route you have defined, next is the second, etc.
When express gets a request, it appears to be matching your route/name of route/middleware, and if it's a hit, it executes the middleware/route and potentially waits for a "next()" call.
So if you have a route "/test" it will only be executed if you have a request matching "/test". routes with different names obviously wont get triggered. middlewares can also have names: app.use("/test", middlewareA). This will also only trigger if "/test" is requested. The way you do it, all requests (within the routes namespace) will be triggered app.use(middlewareA). It's like a wildcard.
Now, to the implications of things being ordered:
Your 404 middleware should only be used AFTER all routes have been defined. that way, when the list reached the 404 middleware, no routes have actually been found.
returning/sending result/not calling next() at the end of a middleware will all potentially create problems in your flow. I wont go into details about this, but be aware of it.
I am guessing your own middleware is added after the 404 middleware. That is probably the problem. If not, you should surrender more of your code so we can take a better look. But remember, order is everything :)

Is there a way to filter out include & script files from a Node.js response?

From within a middleware module, I'm trying to count the number of page requests made from the parent app. Think of it as a generic request monitor that knows nothing about the pages the parent serves. My initial stab at it simply listened for requests and incremented a counter with each response generated, only to find that each page request generated n number of additional responses from all of the included requests (favicon.ico, script files, etc). I expected that, but hoped there was a way to filter out the secondary files.
Is there a way to differentiate between them so that I can ignore the included files in my count?
So far, I've used the request and express-req-metrics middlewares to look at the response properties, but haven't yet seen any property that was helpful.
If you're using middleware to serve static assets, then one solution is to
just reorder your middleware so that static asset requests never make it
to your counter middleware (if they are handled by upstream middleware):
var counter = 0;
app.use(serveStatic('public'));
app.use(function(req, res, next) {
counter++;
next();
})
// ... routes defined down here ...
However, one downside is that, if you don't have a favicon.ico file for
example, the serveStatic middleware will not handle the request and your counter
middleware will count those requests.
Another solution is to write your counter middleware so that it inspects
the request path first to ensure that the path doesn't end in
'.ico', '.js', '.jpg', etc. Here I just use a basic regular expression:
var counter = 0;
app.use(function(req, res, next) {
if (! /(.ico|.js|.css|.jpg|.png)$/i.test(req.path)) {
counter++;
}
next();
})
// ... routes defined down here ...

Express 4 parameter condition

I would like to have the following routes:
// Services without csrf()
router.get('/user/:uid', userRes.findUser, userRes.GETUser);
router.post('/user/:uid', userRes.findUser, userRes.POSTUser);
// Rest of routes, with csrf()
router.use(csrf());
router.post('/user/subscribe', indexRes.POSTSubscribe);
But what happens here is that POST /user/subscribe is matching second route.
I've been reading Express routes parameter conditions but it shows how to filter numbers. I would like to filter 'subscribe' path:
Is there any chance?
You could use router.param:
var staticUserPaths = ['subscribe'];
router.param('uid', function (req, res, next, id) {
if (~staticUserPaths.indexOf(id)) {
next('route');
} else {
next();
}
});
If you move your /user/subscribe route before the /user/:uid route, it will get executed instead of the /user/:uid route for requests to /user/subscribe. Routes/middleware in Express are executed in the order they are attached.

Resources