app.all('*', function(req, res, next) {
vs
app.use(function (req, res, next) {
Whats the difference? doesn't both take in each request to the server?
For the wildcard * path, there's really not much of a meaningful difference at all. It appears to me like the internal implementation may be slightly more efficient for app.use(fn), then app.all('*', fn). And, if you intend for it to run on all routes, then app.use() makes more logical sense to me since what you're really doing is middleware and that's what app.use() is specially designed for.
Summary for app.all('*', fn) vs. app.use(fn):
No difference in order of execution.
app.use() fires regardless of methods, app.all() only fires for parser supported methods (probably not relevant since the node.js http parser supports all expected methods).
Summary for app.all('/test', fn) vs. app.use('/test', fn):
No difference in order of execution
app.use() fires regardless of methods, app.all() only fires for parser supported methods (probably not relevant since the node.js http parser supports all expected methods).
app.use() fires for all paths that start with /test include /test/1/ or /test/otherpath/more/1. app.all() only fires if its an exact match to the requested url.x
Details
All route handlers or middleware that match a given route are executed in the order they were defined so app.all('*', fn) and app.use(fn) do not have any different ordering when placed in identical places in the code.
In looking at the Express code for app.all() it appears that the way it works is that it just goes through all the HTTP methods that the locally installed HTTP parser supports and registers a handler for them. So, for example, if you did:
app.all('*', fn);
The Express code would run these:
app.get('*', fn);
app.put('*', fn);
app.post('*', fn);
app.delete('*', fn);
// ...etc...
Whereas app.use() is method independent. There would be only one handler in the app router's stack that is called no matter what the method is. So, even if an unsupported http verb was issued and the parser let the request get this far, the app.use() handler would still apply whereas the app.all() handler would not.
If you use a path with both app.all() and app.use() that is not just a simple wildcard like '*', then there is a meaningful difference between the two.
app.all(path, fn) only triggers when the requested path matches the path here in its entirety.
app.use(path, fn) trigger when the start of the requested path matches the path here.
So, if you have:
app.all('/test', fn1); // route 1
app.use('/test', fn2); // route 2
And, you issue a request to:
http://yourhost.com/test // both route1 and route2 will match
http://yourhost.com/test/1 // only route2 will match
Because only middleware with app.use() fires for partial matches where the requested URL is contains more path segments beyond what is specified here.
So, if you intend to insert some middleware that runs for all routes or runs for all routes that are descended from some path, then use app.use(). Personally, I would only use app.all(path, fn) if I wanted a handler to be run only for a specific path no matter what the method was and I didn't not want it to also run for paths that contain this path at the start. I see no practical reason to ever use app.all('*', fn) over app.use(fn).
Related
I'm trying to wrap my head around my implementation of express.router() not triggering of the middleware function assigned to it.
I wrote a pretty big app and trying to add a few more endpoints to my path, but for some reason the 9th route gets loaded but does not trigger the function.
app.js
server.use(cors());
server.use(function (req, res, next) {
next();
});
server.use("/", express.static("./assets"));
server.use("/api", api);
server.use("/debug", debug);
server.use("/config", config);
server.use("/control", control);
server.use("/tools", files);
And this is where I declared my routes with the respective functions.
router.get("/teams", onGetTeams);
router.get("/players", onGetPlayers);
router.get("/achievements", getTop3);
router.get("/xpression", onXprPayload);
router.get("/snapshot", onRequestSnapshot);
router.get("/round-timeline", onRequestTimelinePayload);
router.get("/:half", onRequestHalf);
router.get("/dashboard-message", onSetDashboardMessage);
router.get("/get-match-odds", getTeamOdds);
function getTeamOdds(req, res) {
console.log("Sent odds");
res.json(odds);
res.end();
}
When I make the request for the last route, the function does not get executed, and I get back a 200 response.
Is there something big I'm missing?
Thank you !
Your route definition here:
router.get("/:half", onRequestHalf);
is a wildcard route that matches ALL routes so none of the routes after it will get called unless that specific route calls next() to continue routing.
Top level wildcard routes are problematic for this reason. I would suggest avoiding them. There are temporary work-arounds like moving their definition to be the last top level route definition, but they can still be limiting for defining future routes because they are so greedy.
My recommendation would be to not make it a top level route:
router.get("/half/:half", onRequestHalf);
So, it won't conflict with the other top level routes and it essentially has it's own URL scope all to itself.
I'm trying to wrap my head around my implementation of express.router() not triggering of the middleware function assigned to it.
I wrote a pretty big app and trying to add a few more endpoints to my path, but for some reason the 9th route gets loaded but does not trigger the function.
app.js
server.use(cors());
server.use(function (req, res, next) {
next();
});
server.use("/", express.static("./assets"));
server.use("/api", api);
server.use("/debug", debug);
server.use("/config", config);
server.use("/control", control);
server.use("/tools", files);
And this is where I declared my routes with the respective functions.
router.get("/teams", onGetTeams);
router.get("/players", onGetPlayers);
router.get("/achievements", getTop3);
router.get("/xpression", onXprPayload);
router.get("/snapshot", onRequestSnapshot);
router.get("/round-timeline", onRequestTimelinePayload);
router.get("/:half", onRequestHalf);
router.get("/dashboard-message", onSetDashboardMessage);
router.get("/get-match-odds", getTeamOdds);
function getTeamOdds(req, res) {
console.log("Sent odds");
res.json(odds);
res.end();
}
When I make the request for the last route, the function does not get executed, and I get back a 200 response.
Is there something big I'm missing?
Thank you !
Your route definition here:
router.get("/:half", onRequestHalf);
is a wildcard route that matches ALL routes so none of the routes after it will get called unless that specific route calls next() to continue routing.
Top level wildcard routes are problematic for this reason. I would suggest avoiding them. There are temporary work-arounds like moving their definition to be the last top level route definition, but they can still be limiting for defining future routes because they are so greedy.
My recommendation would be to not make it a top level route:
router.get("/half/:half", onRequestHalf);
So, it won't conflict with the other top level routes and it essentially has it's own URL scope all to itself.
i am trying to make node render more faster.
then i want use parallel.
so how to put in routes in parallel function?
before
var app = express();
var index = require('./routes/index')();
var auth = require('./routes/auth')();
app.use('/',index);
app.use('/auth/',auth);
after ( I am trying this)
var app = express();
var index = require('./routes/index')();
var auth = require('./routes/auth')();
function parallel(middlewares){
return function (req, res, next){
async.each(middlewares,function(mw,cb){
mw(req,res,cb);
},next);
};
};
app.use(parallel([
['/',index],
['/auth/',auth],
[others here]
]));
I found a way to do this. It comes with a few caveats which are mostly due to the fact that Express is designed around sequential middleware, but by following a set of guidelines you can make it work just fine.
The Problem Statement
We want to pass in a group of middleware and have them run in parallel (or as parallel as their async operations will allow). If you have multiple independent async things to do in middleware, this should be able to get to an end result quicker (which is pretty much the whole point of doing this).
We want to be able to pass in typical routing paths (with all wildcards and special characters) as in app.use('/product/:id', fn) and then execute only the routes that match the current request "in parallel" with each other
We want Express itself to do all the route matching so we don't have to reimplement or copy any of that and so that everything Express normally supports for route matching is supported.
We want to support route parameters like req.params, even though those may be different for each middleware (not quite so common to use this in middleware, but still part of the Express design).
The Design Scheme
We create our own Router object. To that router object, we add a "start" marker middleware at the beginning (so we can see when routes are starting on this router), then we add a place holder middleware with the proper path for each of our parallel middleware handlers and then we add another "end" marker middleware at the end (so we can see when routes are done on this router). The "start" and "end" routes match all routes so they are always called. The other routes have the path that was passed in for them so they may or may not get called for any given request depending upon whether they match the current path or not.
This router gets added to the routing stack with app.use(router). In this way, the regular Express engine will do all the routing for this router and decide which routes match the current request path. But, rather than execute the regualar middleware functions when it finds a matching route path, it will just execute our placeholder middleware. When it executes the placeholder middleware, we will get to see the "start" middleware, any other middleware that matches the route which we will capture in a list and then the "end" middleware. When we get the "end" middleware, we will have captured the list of middlewares that match the current route and we can then go execute just those actual middlewares in parallel. When all those middlewares are done, we then call next() for our router allowing the rest of routing to continue.
So, in summary, we insert dummy route handlers with the actual route paths and let Express call our dummy route handlers if the path matches as a means of telling us which routes match the current path. Then, we take that list of matching routes and set them up for parallel execution. In this way, Express does all the work of telling us which routes match the current request path.
Implementation
So, to implement this, I define a new app.useParallel() and we add a fourth parameter to the middleware function for req.param that belongs to that specific middleware route definition.
// pass an array of path, fn pairs
// ['/', func1, '/somePath', func2]
app.useParallel = function(array) {
// create a router that will be inserted only for route matching
let router = express.Router();
// insert route at beginning to make start of routes getting called
router.use(function(req, res, next) {
req.routeList = [];
next();
});
// let the router have dummy route handlers with all the right paths
// so we can use it to see which paths it will match
for (let r of array) {
router.use(r[0], function(req, res, next) {
// for each route that actually gets called (and thus must have matched the path),
// save the corresponding callback function and a copy of the req.params
req.routeList.push({fn: r[1], params: Object.assign({}, req.params)});
next();
});
}
// now insert route at end of router that matches all routes to know when we're done
router.use(function(req, res, next) {
let routeList = req.routeList;
if (routeList && routeList.length) {
// now we are ready here to execute the route handlers in req.routeList in parallel
let len = routeList.length;
let doneCnt = 0;
let nextCalled = false;
for (let middleware of routeList) {
middleware.fn(req, res, function(err) {
++doneCnt;
if (err) {
// make sure we only call next() once
if (!nextCalled) {
nextCalled = true;
next(err);
}
} else {
if (doneCnt === len && !nextCalled) {
next();
}
}
}, middleware.params);
}
} else {
next();
}
});
// insert this router in the chain
app.use(router);
}
And, then this is used like this:
function test1(req, res, next, params) {
// some async operation that calls next() when done
next();
}
// similar definitions for test2(), test3() and test4()
app.parallel([['/', test1], ['/', test2], ['/:id', test3], ['/test', test4]]);
Restrictions
Running multiple middlewares potentially in parallel leads to some restrictions on the middleware - all of which seem somewhat expected if you're setting up for parallel operation. Here are some of the restrictions:
You will get interleaved execution of these handlers if any handler uses asynchronous calls and then completes sometime later. Since node.js is still single threaded, this will NOT do parallel execution of purely synchronous middleware handlers. If they are synchronous, they will still be executed synchronously.
The initial synchronous part of each parallel middleware handler (before it returns while waiting for async responses) is still called in proper sequence.
If any middleware calls next(err), the first one to do it will be the only one that gets processed - others will be ignored.
The req object is shared among all the parallel middleware functions. As such, you have to be aware of any race conditions in using it if you have async operations in your middleware writing to the req object. It can certainly be used as a place to store independent properties (different for each middleware), but two parallel middlewares cannot be expecting sequential access to the same property (one sets it and the other reads what was set) because the execution order is unpredictable. So, you are safest if each parallel middleware only reads standard properties and only writes its own properties.
Because the req object is shared, each middleware can't have its own value for req.param like normal middleware would. As such, do not use req.param at all. Instead, each parallel middleware is passed a fourth argument that is the param object. This allows each parallel middleware to have its own param object.
If any middleware actually sends a response (as opposed to just setting up req variables for later route handlers), then you need to know that it's racy. In general, I would not think you'd use parallel middleware to actually send a response, but I could imagine a few rare cases where you just want the first middleware that finds an answer to send the response. If more than one attempts to send a response, you will get a warning about multiple responses (Express will catch it for you). It is not blocked here.
It should go without saying that any async code in these parallel handlers finishes in an arbitrary order. Do not execute handlers in parallel that require any specific ordering relative to each other.
Use of the req.route property in the parallel middleware is not supported.
Minimal Testing So far
I have not exhaustively tested this, but I do have it running in a sample app that just uses random timers to call next() in each of four parallel middlewares. The route matching works. The params feature works. The middlewares do appear to run in parallel and complete in random order (per their random timers).
All parallel route handlers finish before subsequent routing continues.
The only state used during the parallel processing is stored either on the req object (which should be unique to each request) or in closures so it should be safe from race conditions of multiple parallel requests to the server that are in flight at the same time (though I haven't pounded on a server with lots of parallel requests to confirm that).
I am fairly new to the express framework. I couldn't find the documentation for application.post() method in the express API reference. Can someone provide a few examples of all the possible parameters I can put in the function? I've read a couple sites with the following example, what does the first parameter mean?
I know the second parameter is the callback function, but what exactly do we put in the first parameter?
app.post('/', function(req, res){
Also, let's say we want the users to post(send data to our server) ID numbers with a certain format([{id:134123, url:www.qwer.com},{id:131211,url:www.asdf.com}]). We then want to extract the ID's and retrieves the data with those ID's from somewhere in our server. How would we write the app.post method that allows us to manipulate the input of an array of objects, so that we only use those object's ID(key) to retrieve the necessary info regardless of other keys in the objects. Given the description of the task, do we have to use app.get() method? If so, how would we write the app.get() function?
Thanks a lot for your inputs.
1. app.get('/', function(req, res){
This is telling express to listen for requests to / and run the function when it sees one.
The first argument is a pattern to match. Sometimes a literal URL fragment like '/' or '/privacy', you can also do substitutions as shown below. You can also match regexes if necessary as described here.
All the internal parts of Express follow the function(req, res, next) pattern. An incoming request starts at the top of the middleware chain (e.g. bodyParser) and gets passed along until something sends a response, or express gets to the end of the chain and 404's.
You usually put your app.router at the bottom of the chain. Once Express gets there it starts matching the request against all the app.get('path'..., app.post('path'... etc, in the order which they were set up.
Variable substitution:
// this would match:
// /questions/18087696/express-framework-app-post-and-app-get
app.get('/questions/:id/:slug', function(req, res, next){
db.fetch(req.params.id, function(err, question){
console.log('Fetched question: '+req.params.slug');
res.locals.question = question;
res.render('question-view');
});
});
next():
If you defined your handling functions as function(req, res, next){} you can call next() to yield, passing the request back into the middleware chain. You might do this for e.g. a catchall route:
app.all('*', function(req, res, next){
if(req.secure !== true) {
res.redirect('https://'+req.host+req.originalUrl);
} else {
next();
};
});
Again, order matters, you'll have to put this above the other routing functions if you want it to run before those.
I haven't POSTed json before but #PeterLyon's solution looks fine to me for that.
TJ annoyingly documents this as app.VERB(path, [callback...], callback in the express docs, so search the express docs for that. I'm not going to copy/paste them here. It's his unfriendly way of saying that app.get, app.post, app.put, etc all have the same function signature, and there are one of these methods for each supported method from HTTP.
To get your posted JSON data, use the bodyParser middleware:
app.post('/yourPath', express.bodyParser(), function (req, res) {
//req.body is your array of objects now:
// [{id:134123, url:'www.qwer.com'},{id:131211,url:'www.asdf.com'}]
});
Hellow I have code in my app.js, looking like that:
app.use('/someurl', require('./middleware/somemodule'));
-app.use instead app.all
and module looks like:
if(process.env.BLALAL === undefined){
throw "Error: process.env.BLALAL === undefined";
}
module.exports = function(req, res, next){
...
}
is it a bad practice ?
As said on the express api reference:
app.VERB(path, [callback...], callback)
The app.VERB() methods provide the routing functionality in Express,
where VERB is one of the HTTP verbs, such as app.post().
app.use([path], function)
Use the given middleware function, with optional mount path,
defaulting to "/".
The "mount" path is stripped and is not visible to the middleware
function. The main effect of this feature is that mounted middleware
may operate without code changes regardless of its "prefix" pathname.
IMO
The functionality may be nearly the same, but there is an underlying semantic meaning. The routes itself should be set through the app.VERB api, while any middleware should be set through the app.use api.
Normally middlewares modify the request or response objects, or inject functionality from other module that may answer the request, or not.
connect.static is a good example. It could be really an app or an HttpServer by itself, but is injected as middleware on other app object.
I personally don't like require inside other commands then var bla = require('bla');, it makes code much worse readable in my opinion and you did not get anything in return.
I am not sure what was your intention, but if your code depends on environment variable, it is better to throw immediately than later when your route is called. So app.use is better then app.all. But I don't understand why aren't you simply test your condition inside app.js and why you hide it in somemodule.