Understanding Express.js middleware precedence - javascript

I'm reading the two examples in the Express.js API reference but I don't get them.
Example No. 1
Now suppose you wanted to ignore logging requests for static files, but continue logging routes and middleware defined after logger(). You could simply move static() above it:
app.use(express.static(__dirname + '/public'));
app.use(logger());
// other middleware
How does this cause requests for static files not to be logged? Isn’t all middleware executed (in sequence) for every request?
Example No. 2
Another concrete example would be serving files from multiple directories, giving precedence to "./public" over the others:
app.use(express.static(__dirname + '/public'));
app.use(express.static(__dirname + '/files'));
app.use(express.static(__dirname + '/uploads'));
I suspect that for e.g. a request like "/js/stuff.js", the first middleware checks if "/public/js/stuff.js" exists. If it does, this middleware handles the request and none of the subsequent middleware is executed (sort-of like an early return). If this path however doesn't exist, this middleware passes the request to the next middleware in line. Is this correct?
Please explain both examples!

Express routes are just a collection of middleware. Every request to the server is passed along the middleware chain.
A middleware function has the signature
function(req, res, next) { }
You can add middleware to the chain with app.use(), as you've seen above.
Each middleware has two choices. It can
Pass the request to the next middleware in the chain, or
End the request chain and send a response
If a middleware fails to do either of these, you'll see your request time out and just "spin" endlessly.
To pass a request along, the middleware must call next(). The third argument passed to a middleware is this next() function. It might have a side effect, like the logger middleware above.
To end a request, the middleware can use one of several methods attached to the res object, such as res.send() or res.end() to send a response back to the requestor. So the express.static middleware has the behavior that, if it finds the requested file, it ends the request chain and sends the file. If it doesn't find the requested file, it passes the request to the next middleware.

Related

Why am i getting the output twice in the Node console?

I have just started learning NodeJS, Kindly help me understand this
const http = require('http');
const express = require('express');
const app = express();
app.use((req, res, next) => {
console.log('In the Middleware');
next();
});
app.use((req, res, next) => {
console.log('In another Middleware');
res.send('<h1>Hello From Express</h1>');
});
app.listen(3000);
Output is
In the Middleware
In another Middleware
In the Middleware
In another Middleware
Expected
In the Middleware
In another Middleware
Browsers will often make multiple requests to a server. For example, they will usually try to fetch a favicon.ico file. Another example is a CORS preflight request.
If you open the developer tools in your browser, go to the Network tab, and then refresh your page, you will see all the requests the browser makes (you may need to check the "Disable cache" checkbox first). If you see more than one request, that's probably the reason you're seeing your text logged multiple times.
Another simple way to test this is to try making a request to your server from a client other than your browser. For example, run this from the command line: curl http://localhost:3000. That command should make only a single request to your server. Do you see your text output multiple times in that case? If not, then that's further evidence your browser is making multiple requests to your server.
I would say that this happens because the browser usually makes a request for the favicon.ico as well, but you can check in the Network tab of the developer tools.
In my case, i was using:
app.use('/',function(req,res){
console.log('here');
})
So, I though whenever I refresh my frontend this should run once. But, browser actually sends multiple request whenever you refresh. (i.e favicon)
That's the reason your code logging multiple times.

Nodejs: Middleware for only page loading

I'm working with nodejs and ejs template. I want to set a middleware which will be called only when page loading, not when I send request from code.
Example:
app.use(function(req, res, next){
if(req.session){
console.log("OKAY");
}
next();
});
I want this log appears only on page loading, not when I send request from code like below
$.get( "/users", function( data ) {
console.log(data);
});
How can I do this ?
Thank you
You have a couple options:
In your middleware, you can check req.path to see if it's a path that you should apply the middleware to or not and use an if in your middlware to either just call next() without doing anything or to do whatever the middleware is designed to do.
You can design your routes to that page routes and ajax routes are on separate paths and then design a router for page routes and a router for ajax routes and put the middleware only on the page router.
It will really help you a lot (with either option above) if you design your URLs so it's easy for your server to distinguish whether this is a URL that should or should not have the middleware applied. Usually, the simplest way to do that is to use a known prefix on one or both branches of your URL design. For example, all ajax URLs could start with /api and then you can easily shunt all API calls off to a special router and all other URLs are non-API URLs (probably page URLs).
Here's an example of the separate API router:
// split off all API calls to a separate router
let apiRouter = express.Router();
app.use('/api', apiRouter);
// handle /api/users
apiRouter.get('/users', handleUserAjaxRequest);
// handle all other /api/xxx routes that don't have their own handler
apiRouter.use(function(req, res, next) {
// if /api request not handled by here, then don't allow it to propagate further
// it must be a invalid /api/xxx URL, so do a 404
res.status(404).end();
});
// this won't get called if there's a /api/xxx URL because that will have
// already been handled by the apiRouter
app.use(someMiddleware);
app.get('/somepage', handleSomePageURL);
You could also use a separate router for all your page requests which might make modularity a little cleaner with all the API routes in one module and all the page routes in another module, each exporting their own router.
I'm using JQuery to send request from client and I saw from jfriend00's link that req.xhr returns a Boolean property that is true if the request’s X-Requested-With header field is “XMLHttpRequest”, indicating that the request was issued by a client library such as jQuery.
app.use(function(req, res, next){
if(req.xhr){
console.log("FROM CLIENT LIBRARY");
}
next();
});
Thank you jfriend00

Can objects attached to requests in expressjs be tampered with?

In express.js we often attach objects to the req object in middleware, e.g. req.myObject. What prevents a user sending an http request that includes req.myObject already set to some value? For example, I could use req.myObject as part of authentication. Could a user set req.myObject = true when sending a request when it should really be false? Potentially an issue if req.myObject is set on some routes but not others but middleware that checks req.myObject is re-used across routes.
req is an object created by Express when a request is received. It's not something passed directly from client to the server, in fact it isn't even available to client.
A client can only relay information to the server in some limited ways - GET query, POST form data, or route paths which are attached to the req object by Express as req.query, req.body, and req.params respectively.
Anything else attached to the req object is out of scope of the client, at least directly.
Related question: Node.js request object documentation?

how to redirect express.js request directly to 404

I would like to send a request to a certain route within express.js directly to 404 if the user is not authenticated.
in my middleware I have the following code:
exports.isAuthenticated = function (req, res, next) {
if (req.isAuthenticated()) {
next();
} else {
res.redirect("/login");
}
};
what I would like to do instead is to present the user with a 404 page instead. I have configured one globally, but I dont know how I am supposed to skip every chained middleware for a request and send a user to 404 directly.
Thanks for answers :)
okay I got the answer. I have to use
If you need to skip the rest of the middleware from a router
middleware stack, call next('route') to pass on the control to the
next route. Note: next('route') will work only in middleware loaded
using app.VERB() or router.VERB().
according to http://expressjs.com/guide/using-middleware.html and its working

How can a Node.js library register for HTTP requests on a particular URL path?

I am writing a library for a web service in Node.js. My library needs to handle all HTTP requests with a particular URL prefix (Eg, /_docs/*).
I want people to be able to use my library without changing much of their code.
The API should look something like this:
server = http.createServer(function(req, res) { ... });
...
myLibrary.listen(server, '_docs/');
or
server = new http.Server();
myLibrary.listen(server, '_docs/');
server.on('request', function(req, res) { ... });
If I merely register another event handler on the server object, the user's http request handler will be called on all HTTP requests as well. My code will race with the user's 404 handler.
Socket.io has a similar problem, and they solve it by making their .listen() function move all existing http request handlers into a private array. When HTTP requests come in, if their code doesn't handle the URL it calls the listeners in the array. However, as far as I can tell this wouldn't work in the second example I've shown above.
Whats the best way to make this work?
What about Connect? Router middleware provides rich Sinatra / Express-like routing.
Example
connect.router(function(app){
app.get('/user/:id', function(req, res, next){
// populates req.params.id
});
app.put('/user/:id', function(req, res, next){
// populates req.params.id
});
})
For advanced use look at http://expressjs.com/guide.html#routing.

Categories