404 usage with router and different routing files - node.js

I use in my app different routes. All this routes have a topic file. Like:
index.js -> for basic routing in the / level. Like /welcome or
/dashboard
cases.js -> for using edit forms Like /cases/case_create
tcafe.js -> for testing routes like /tcafe/startit
users.js -> for user operation like /users/login or /users/register
In my app I use:
// Routes
app.use('/', require('./routes/index.js'));
app.use('/users', require('./routes/users.js'));
app.use('/cases', require('./routes/cases.js'));
app.use('/tcafe', require('./routes/tcafe.js'));
Ok, now I want to add a 404 handler so I can avoid "Cannot GET /dashboard2"
I added now to the end of all route files:
router.use((req, res, next) => {
next({
status: 404,
message: 'Not Found',
});
});
router.use((err, req, res, next) => {
if (err.status === 404) {
return res.status(400).render('404');
}
if (err.status === 500) {
return res.status(500).render('500');
}
next();
});
now I get a 404 if using "/dashboard2" but all other routes also get a 404
like "/users/login" or "/cases/create_case"
Moving the code to the main js file (server.js) also do not work.
Anybody has a Idea how to protect the whole app with 404 for all routes?

As stated in the official Express FAQ:
All you need to do is add a middleware function at the very bottom of the stack (below all other functions) to handle a 404 response
So in your case, you need to put your 404-handler after all of the router.use() calls.

Related

express gives error 404 on when trying to visit existing route

I have created a route to 404.html page if user enters incorrect url route
app.use(function (req, res, next) {
res.status(404).sendFile('public/404.html', {root: __dirname})
})
The problem is that when I enter existing route (in this case I use oauth google authentication) it still leads me to 404 page I created but It should redirect me to google login page.
app.get('/google', passport.authenticate('google', { scope: ['profile', 'email'] }));
Same with logout, it leads me to 404 page
app.get('/logout', (req, res) => {
console.log(`\n`);
console.log('\x1b[1m\x1b[31m', `*** User ${req.user.displayName} has logged out ***`);
req.session = null;
req.logout();
res.redirect('/');
});
Your 404 route needs to be the last route you declare. The declaration order matters. This way, the 404 route handler executes ONLY when no other route has already handled the request (which is what you want it to do).
In Express, routes attempt to match the incoming request in the order the route handlers are registered. Since your 404 handler matches all routes, it has to be last so that it comes into play only when no other route handler has already taken the request.
This is what I always use:
// Pages
app.get('/file', function(req, res){
res.sendFile('/path/to/file.html');
});
// 404
app.get('*', function(req, res){
res.sendFile('/path/to/404/file.html');
res.statusCode = 404;
});
Make sure the 404 handler is after all existing responses, and make sure you restart your server after updating.

Catching error when URL param does not match regex in Express

I have some code below:
app.get('/tx/:txhash([a-zA-Z0-9]{20,50})', (req, res) => {
//do some work
}
My issue is if the parameter does not match the regex pattern, I get
Cannot GET /tx/8241fesf
But I'm not sure how to have a custom error or redirect. I tried to read the res object but it seems it's skipped altogether and haven't found the answer searching on SO.
You can handle 404 withing express handlers.
In your main express file(may be index.js or app.js) just put following after your routing middleware.
app.use("/", your_router);
// catch 404 and forward to error handler
app.use((request, response, next) => {
// Access response variable and handle it
// response.status(404).send("Your page is not found"))
// or
// res.render("home")
});

Express 4: Handle every and all errors

While coding my app, I sometimes had a little mishap when typing my URLs in the browser, and thus sometimes got the error message:
Cannot GET /some/route
Which was true, since the route may was not defined.
But since this app is planned to enter production, I kinda don't want to use this flat message as my "error page".
Looking into the Express 4 docs, they tell me to .use() a middleware with 4 arguments. I did that. But I'd still get this issue...
Turns out that this message comes from the finalhandler module and my bet is, that this middleware comes before my error-catching, 4-argument middleware.
Here is a basic express app that I threw together while trying to find a solution:
var app = require("express")();
app.use("/yo", function(req, res, next){
res.send("Yo!");
});
app.use(function(error, req, res, next){
res.send("An error: "+error);
console.log(error);
});
app.listen(10000);
Accessing /yo works. But, / or /derp yields the Cannot GET message instead of my little middleware.
So, how is this done correctly, now?
The error middleware is only for actual errors, such as a middleware or route handler throwing an exception or passing an error to next().
If you want to provide a route handler for requests that do not match any existing routes, then just add a middleware after all of your app's routes/middleware like:
var app = require("express")();
app.use("/yo", function(req, res, next){
res.send("Yo!");
});
app.use(function(req, res, next) {
res.send('Could not route your request!');
});
app.use(function(error, req, res, next){
res.send("An error: "+error);
console.log(error);
});
app.listen(10000);

How to manage HTTP errors in Node.js

Hi I'm developing my first Node.js application and I found my first issue in something really basic, I can't catch the HTTP errors (404, 500, ...)
I've followed the doc (I think so) but I suppose that I'm missing something.
This is my code:
var express = require('express')
app = express()
app.use(express.logger('dev'));
app.get('/', function(req, res) {
res.send('Hellow World!!!')
})
app.use(app.router);
app.use(function(err, req, res, next) {
console.error('Oh!! ERROR');
console.error('My ERROR: ' + JSON.stringify(err));
});
app.listen(3000);
console.log('Server running at http://127.0.0.1:3000/');
Thanks in advance.
So the way express works is if it hits the end of the entire stack of middleware and route handlers and nothing has responded yet, it's going to send the fallback 404 response automatically without raising an error. This is why your error handling middleware isn't being called. By default, express doesn't consider a 404 an error, which is probably the right way to think of it.
If you want to customize this, you can put a middleware at the end of your stack to either serve a custom 404 page directly or call next with an error if you prefer that way.
app.get('/'...
app.get('/two'...
app.get(/'three'...
app.use(middleware1...
app.use(middleware2...
app.use(app.router);
app.use(function (req, res, next) {
//Option 1: respond here
return res.status(404).render('my_404_view');
//Option 2: trigger error handler
return next(new Error('404ed!'));
}
Option 2 will trigger your error handling middleware. There you will have to get info from the error object to determine the desired view to render and status code to send. I personally define an errors.NotFound class that has a 404 code and lets me render a friendly 404 page view.

Sharing 404 page across node.js apps connected via VHOST

I am sorta new to node.js and web programming in general so excuse if I ask strange questions :D
So here is the way I am setting up my express node.js project.
I have a top level app.js simply to redirect traffic to a few subdomains:
var app = module.exports = express.createServer(options);
app.use(express.vhost('blog.localhost', require('./apps/blog/blog.js')));
app.use(express.vhost('app1.localhost', require('./apps/app1/app1.js')));
app.use(express.vhost('login.localhost', require('./apps/login/login.js')));
In each of the sub-apps, that is included via require(), I simply return a new express server:
module.exports = express.createServer(options);
What is the most elegant way to set up a 404 page? When I was just using a single app, I simply used
app.use(function(req, res, next){
res.render('404', {
});
});
But if I use this method, I am going to have to create a 404.jade for every app and I dislike useless duplications in code. Any idea how to share a single 404 logic across multiple vhosts?
You have 3 hosts that require 3 route files. My suggestion is to require in each this 404 route, from an external file.
This way you would have the 404 route for every host, but it will just reside in one place.
Example:
404 route file - 404.js
module.exports = function (app, req, res, options) {
app.get('/404', function(req, res, next) {
res.render('404', { options: options });
});
}
routes for host A
// define other routes here
...
// you pass the app, req, res as params
// the last param is for local vars sent to the view
require('./routes/404.js')(app, req, res, { host: 'HostA' });

Resources