I got some code from a tutorial where express is used to make a NodeJS Proxy, they eventually use express.use with an empty string for the path. I can't find what the empty string will do is it the same as '/'?
The code looks like this :
app.use('', (req, res, next) => {
if(req.headers.authorization.includes('Bearer')){
next();
} else {
res.sendStatus(403);
}
})
It is not the same as /. It means that middleware will be used every time a request hits your server.
You can remove it for brevity.
app.use((req, res, next) => {
if(req.headers.authorization.includes('Bearer')){
next();
} else {
res.sendStatus(403);
}
});
Related
I am using express with a pattern like this :
app = express();
router = express.Router();
router.use((req, res, next) => {
console.log("my middleware before");
next();
});
router.get('/foo', (req, res, next) => {
console.log("My route");
res.send("<h1>Hello</h1>")
next();
});
router.use((req, res, next) => {
console.log("my middleware after");
});
app.use("/", router);
app.get("*", (req, res, next) => {
console.log("page not found");
throw new Error("Not Found");
});
app.use((err, req, res, next) => {
console.log("Error occure");
res.send("<h1>Error</h1>");
});
app.listen(3000);
When I request '/foo' I would like to have
> my middleware before
> My route
> my middleware after
<h1>Hello</h1>
And when I request anything else :
> page not found
> Error occure
<h1>Error</h1>
But the page not found route is executed in each case, even if route '/foo' is done.
How can I get it working ?
When I run your code, I do not get the output you show, so something about your real code is apparently different than what you show in your question.
I do get a slightly confusing output and that happens because the browser sends both the /foo request and a /favicon.ico request. When I run it, the /foo request generates the desired output. The /favicon.ico request generates some middleware output and then gets stuck in the router.
If you filter out the /favicon.ico route (so that it doesn't confuse things) by adding this as the first route:
app.get("/favicon.ico", (req, res) => {
res.sendStatus(404);
});
Then, I get exactly this output in the server logs when I request /foo:
my middleware before
My route
my middleware after
Which is exactly what you asked for.
There is, however, a general problem with this:
router.use((req, res, next) => {
console.log("my middleware after");
});
Because it will catch and hang any legit requests that haven't yet had a response sent. You can't really code it that way unless you only don't call next() if a response has already been sent.
As a bit of a hack, you could do this:
router.use((req, res, next) => {
console.log("my middleware after");
// if response hasn't yet been sent, continue routing
if (!res.headersSent) {
next();
}
});
But, there is probably a better way to solve whatever problem you're actually trying to solve. If, in the future, you describe your real problem rather than a problem you have with your solution, then you allow people to offer a wider range of solutions to your real problem including things you haven't even thought of to try. As your question is written right now, we're stuck down the solution path you followed and don't know what the original problem was. That is, by the way, referred to as an XY Problem.
Do this
app = express();
router = express.Router();
router.use((req, res, next) => {
console.log("my middleware before");
next();
});
router.get('/foo', (req, res, next) => {
// use locals to record the fact we have a match
res.locals.hasMatch = true
console.log("My route");
res.send("<h1>Hello</h1>")
next();
});
router.use((req, res, next) => {
console.log("my middleware after");
});
app.use("/", router);
app.get("*", (req, res, next) => {
console.log("page not found");
throw new Error("Not Found");
});
app.use((err, req, res, next) => {
// check locals to see if we have a match
if (!res.locals.hasMatch) {
console.log("Error occure");
res.send("<h1>Error</h1>");
}
});
app.listen(3000);
You can utilize middlewares and even nest them.
You can implement it like this:
Middlewares
const before = (req, res, next) => {
console.log("my middleware before");
next(); // Supply next() so that it will proceed to the next call,
// in our case, since this is supplied inside the router /foo, after this runs, it will proceed to the next middleware
};
const after = (req, res, next) => {
console.log("my middleware after");
};
Route
// Supply "before" middleware on 2nd argument to run it first when this route is called
router.get('/foo', before, (req, res, next) => {
console.log("My route");
res.send("<h1>Hello</h1>");
next(); // Call next() to proceed to the next middleware, or in "after" middleware
}, after); // Supply the "after" middleware
Once ran, it will proceed with this desired result sequence:
> my middleware before
> My route
> my middleware after
Unmatched Routes Handler
Instead of this
app.get("*", (req, res, next) => {
console.log("page not found");
throw new Error("Not Found");
});
You can implement it like this instead, this is after your app.use("/", router); -- This will handle your unmatched routes:
Sources:
https://stackoverflow.com/a/44540743/6891406
https://stackoverflow.com/a/16637812/6891406
app.use((req, res, next) => {
console.log("page not found");
res.json({ error: 'Page not Found' })
});
I have an API written in Node.JS/Express and an Angular client that talks to it, both in the same server. All HTTP calls that are not recognized by the API are automatically redirected to the client.
My current code looks like this and it is working as expected so far:
app.get('/api/something', (req, res) => {
//...
});
app.get('/api/foo/bar', (req, res) => {
//...
});
// (...)
app.use(express.static('client'));
app.get('/*', (req, res) => {
res.sendFile('client/index.html', { root: path.join(__dirname, '..') });
});
Now I need to add to this a route to a directory with static files (for example, stuff, so that URLs like /stuff/xxx/yyy.png would return the corresponding file), but still falling back to the Angular client for everything else.
How can I achieve this? So far, everything I tried would either not work at all or break the client routes.
Edit: Based on the answer by joyBlanks, this is what ended up working for me:
(The redirect is necessary to correctly handle URLs that point to a directory name without the trailing slash)
app.get('/*', (req, res, next) => {
if (req.url.startsWith('/stuff')) {
res.sendFile(
req.url.substr(1), { root: path.join(__dirname, '..') },
err => {
if (err) {
if (err.code == 'EISDIR')
res.redirect(req.url + '/');
else
next(err);
}
}
);
}
else {
res.sendFile('client/index.html', { root: path.join(__dirname, '..') });
}
});
app.get('/*', (req, res, next) => {
if(req.url.contains('/stuff/xxx')){ // or regex match maybe
next();
} else {
res.sendFile('client/index.html', { root: path.join(__dirname, '..') });
}
});
You can add a condition matching the URL. inside this all block
Here's my code
mysql = require('mysql');
con = mysql.createConnection(connectionSetttings);
app.get('/users/list', ensureLogin, function (req, res, next) {
con.query(query.getUserList, [req.user.innId], function (err, rows) {
if (err) {
next(err); // also tried: return next(err)
} else {
displayUsers();
}
});
}, function (err) {
console.error(err);
displayErrorPage(500);
});
I run it with the MySQL server not running to see if Express would render the error page or not. The problem is, Express simply barfs up the stack into the browser. Is there anything wrong with my code? How do I properly chain middlewares?
Define error-handling middleware functions in the same way as other middleware functions, except error-handling functions have four arguments instead of three: (err, req, res, next).
Make sure to add the error handling to the app afterthe routes.
var app = require('express')();
app.get('/users/list', ensureLogin, function (req, res, next) {
con.query(query.getUserList, [req.user.innId], function (err, rows) {
if (err) {
next(err);
} else {
displayUsers();
}
});
});
// Error handling middleware
app.use(function (err, req, res, next) {
displayErrorPage(500);
});
When using MySQL as a session store, session-related middlewares attached using app.use() will intercept requests for all routes and malfunctions. This will make seemingly unrelated routes throw HTTP500 even if it doesn't look like they invoke return next(err).
The solution to this is to only attach any session-related middleware to necessary routes. Alternatively, you can wrap them in a filter function like this one:
var middlewareFilter = function(middleware) {
// Return whatever function that is returned by this function
// to be used in app.use()
return function (req, res, next) {
// Set the routes to be ignored.
var exceptionList = [
'images',
'stylesheets',
'scripts'
];
// Cast req.url to string so it can use JS's string methods
var path = String(req.url);
// If path matches any of the exceptionList...
if (array.contains(path.split('/')[1], exceptionList)) {
// ...just do nothing
return next();
} else {
// Otherwise, return the middleware
return middleware(req, res, next);
}
}
}
And use them like app.use(session(sessionConfig));
I would like to add an optional referral parameter to every URL of my node.js app. I could do the following, but I am thinking about a more efficient/elegant way of achieving this, so my code won't end being too long unnecessarily:
app.get('/product/:example/', function (req, res) {
res.render('product.ejs', { product : product[req.param('example')] });
});
app.get('/product/:example/referrer/:user/', function (req, res) {
// do referral stuff
res.render('product.ejs', { product : product[req.param('example')] });
});
I am thinking about something like this (which obviously doesn't work):
app.get('/product/:example/', function (req, res) { ... });
app.get('/category/:example/', function (req, res) { ... });
// set up all GET requests ...
app.get('/*/referrer/:user/', function (req, res, next) {
// do referral stuff
req.next();
});
Thanks!
Jorge
EDIT: Thank you for your response, mvuajua. I played around with it and I figured out the following. I hope this will help someone:
app.use(function(req, res, next) {
if (req.url.search('/referrer/') > -1) {
res.redirect(req.url.substring(0, req.url.search('/referrer')));
var referrer = req.url.substring(req.url.search('/referrer/')+10,req.url.length);
// do stuff with referrer;
} else {
next();
}
});
You can use a middleware, something like
app.use(function(req, res, next) {
// do stuff here
next();
});
You can also scope it to specific routes, with regular expressions if needed (not sure if that one will work, play around with it a bit until it fits your needs):
app.use(/(.*)\/referrer\/(.*)/, function(req, res, next) {
// do stuff here
next();
});
You still need to account for the parameter in your routes though (or they won't match), or do a redirect in the middleware to the url without the referrer part.
I have a express route like this:
app.get('/', auth.authOrDie, function(req, res) {
res.send();
});
where authOrDie function is defined like that (in my auth.js module):
exports.authOrDie = function(req, res, next) {
if (req.isAuthenticated()) {
return next();
} else {
res.send(403);
}
});
Now, when the user is not authenticated, I would like to verify if the http request has a Authorization (Basic) header. To do that, I would like to use the great connect middleware basicAuth().
As you know, Express is built on top of Connect, so I can use express.basicAuth.
The basicAuth is generally used like that:
app.get('/', express.basicAuth(function(username, password) {
// username && password verification...
}), function(req, res) {
res.send();
});
But, I would like to use it in my authOrDie function like that:
exports.authOrDie = function(req, res, next) {
if (req.isAuthenticated()) {
return next();
} else if {
// express.basicAuth ??? ******
} else {
res.send(403);
}
});
****** How can I call the basicAuth function with the good parameters (req ? res ? next ? ...).
Thanks.
Calling the express.basicAuth function returns the middleware function to call, so you'd invoke it directly like this:
exports.authOrDie = function(req, res, next) {
if (req.isAuthenticated()) {
return next();
} else {
return express.basicAuth(function(username, password) {
// username && password verification...
})(req, res, next);
}
});