Imm Imm - 1 month ago 11
Javascript Question

Routing an Invalid Request to a 404 Error Page

I'm trying to build a server that user will be able to enter this valid urls if the directory exist:

localhost:9090/admin
localhost:9090/project1


but if the directory doesn't exist it should render a 404.html page

how do i go about it

this is my code which i have tried out

app.js

var express = require('express');
var app = express();
var path = require('path');
var routes = require('c:/monex/routes/index');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');

app.engine('html', require('ejs').renderFile);
app.set('view engine', 'html');
app.use(express.static('c:/monex/admin'));
app.use('/', routes);
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(cookieParser());


var server = app.listen(9090, function () {
var host = server.address().address
var port = server.address().port
console.log("MonexJS listening at", port)
})


route.js

'use strict';
var express = require('express');
var app = express();
var router = express.Router();

app.engine('html', require('ejs').renderFile);
app.set('view engine', 'html');

/* GET home page. */
router.get('/', function(req, res) {
res.render('index');
});

router.get('/:projectname', function(req, res) {
var name = req.params.projectname;
res.render('c:/monex/myprojects/' + name +'/index');
});


app.use(function(req, res, next){
res.status(404).render('c:/monex/404.html', {title: "Sorry, page not found"});
});

module.exports = router;

Answer Source

Expressjs has a pretty cool way of handling errors and routing them.

1/ To Confirm if project exists
We use the filesystem module to confirm if it exists, using the access API, you can read more on the module at https://nodejs.org/dist/latest-v6.x/docs/api/fs.html

var fs = require('fs') // We'll need to ask the filesystem if it exists    
var projectname = 'myfolder';

// Excerpt from your code, but Modified
router.get('/:projectname', function(req, res) {
   var name = req.params.projectname;
   fs.access(name, fs.constants.F_OK, function(err) {
      if(!err) { // directory exists
         res.render('c:/monex/myprojects/' + name + '/index'); 
         return;
      }
      // Directory does not exist
      next({statusCode: 404});
   })
});

2/ To route the error properly From the above code, we said anytime directory does not exist in nodejs, call next with an error object, i.e next(err), the difference between next() and next(err) is that there are two types of middlewares in expressjs, the first is:

app.use("/", function(req, res, next) {})

while the second is

app.use("/", function(err, req, res, next) {})

The difference between the two is that, the first one is a normal middleware that routes requests through. But the second is called a error handling middleware. Anytime that next function is called with an argument, express jumps to route it through error handling middlewares from there on. So, to solve your problem.

You will want to solve this at the app level so that all across all routers, you can have 404 pages delivered.

In app.js

function Error404(err, req, res, next) {
   if(err.statusCode === "404") {
      res.status(404).render('c:/monex/404.html', {title: "Sorry, page    not found"});
   }

   // YOu can setup other handlers
   if(err.statusCode === "504") {}
}

app.use('/', routes);
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
   extended: true
}));
app.use(cookieParser());
app.use(Error404);

REFERENCES
http://expressjs.com/en/guide/error-handling.html

https://www.safaribooksonline.com/blog/2014/03/12/error-handling-express-js-applications/

https://github.com/expressjs/express/blob/master/examples/error-pages/index.js