How should I handle routes in Express when users enter random URL's that include multiple forward slashes?
For URL's that don't match actual directories I can do this but it is really horrible. When i go to mysite.com/randomNoise/anythingHere/blahblah the following will render my 404...
app.get('/:anything1/:anything2/:anything3', (req, res) => {
res.render("../theme/404")
})
Like I said, it's not very nice and will not work when even more sub directories are added, I end up with the standard cannot GET / etc Example:
mysite.com/something/somethingelse/whatever/extraGarbage
Is there a way to stop Express sending "Cannot GET /" messages or a way to handle when that happens?
You'll be wanting a custom express error handler.
Put code like this after all other app.use() express calls. It takes advantage of the fact that calling next() with a parameter is how you tell express to return an error, rather than a result, to a user.
const createError = require('http-errors')
...
app.use(function (req, res, next) {
next(createError(404, req.path + ' not found.'))
})
app.use(function (err, req, res, next) {
/* display a message */
res.locals.message = err.message
/* suppress the traceback when not in development */
res.locals.error =
req.app.get('env') === 'development' ? err : {}
if (req.accepts('html')) {
res
.status(err.status || 500)
.render('error')
} else if (req.accepts('json')) {
res
.status(err.status)
.json({
status: err.status,
name: err.name,
message: err.message
})
} else {
res
.status(err.status)
.send(`${err.status}: ${err.message}\r\n`)
}
})
and create yourself an error.pug template, or use whatever template engine you chose.
You can fiddle around with this code to give the exact error presentation you want.
I have written an API to view logs of my server in browser. I tried but not getting how to do error handling. Please show how will you do error handling. I am new to node.js
app.get('/logs', function(request, response, next) {
res.sendFile('file', 'path');
});
Error handling looks something like this below.
app.get('/logs', async function(req, res) {
let something;
try {
something = await "file processing";
} catch (error) {
res.status(500).json({ error: error.toString() });
}
res.json({ something });
});
when you are fetching API from other endpoint, you can use promise or async-await
when something goes wrong in the try statement, then error will be catched
if you want to make error deliberately, using new Error() in try statement
you can also study express error middleware when trying to handle route errors.
I'm using a custom error page in Express, as explained here.
But when I do that, I only see the error message. I'd like to get hold of the same information as displayed in the default Express error handler (the stacktrace, etc.), so that I can:
Log it to the console (if I could leave the default in place for this, I'd be happy).
Display it on the error page, but only for localhost.
How do I do this?
This is a modified version from #generalhenry's answer. You can access the stack trace
in err.stack so you can pass it on your '500' view and do some fancy css styles on it.
app.use(function(err, req, res, next) {
if (err instanceof NotFound) {
res.render('errors/404');
} else {
res.render('errors/500', {error: err, stack: err.stack});
}
});
function NotFound() {
this.name = "NotFound";
Error.call(this, msg);
Error.captureStackTrace(this, arguments.callee);
}
// below all route handlers
// If all fails, hit em with the 404
app.all('*', function(req, res){
throw new NotFound;
});
Just use the error provided to the middleware
// Handle 500
app.use(function(error, req, res, next) {
console.error(error);
if (ISLOCALHOST()) {
res.json(error, 500);
} else {
res.send('500: Internal Server Error', 500);
}
});
My node.js app is modeled like the express/examples/mvc app.
In a controller action I want to spit out a HTTP 400 status with a custom http message.
By default the http status message is "Bad Request":
HTTP/1.1 400 Bad Request
But I want to send
HTTP/1.1 400 Current password does not match
I tried various ways but none of them set the http status message to my custom message.
My current solution controller function looks like that:
exports.check = function( req, res) {
if( req.param( 'val')!=='testme') {
res.writeHead( 400, 'Current password does not match', {'content-type' : 'text/plain'});
res.end( 'Current value does not match');
return;
}
// ...
}
Everything works fine but ... it seems not the the right way to do it.
Is there any better way to set the http status message using express ?
None of the existing answers accomplish what the OP originally asked for, which is to override the default Reason-Phrase (the text appearing immediately after the status code) sent by Express.
What you want is res.statusMessage. This is not part of Express, it's a property of the underlying http.Response object in Node.js 0.11+.
You can use it like this (tested in Express 4.x):
function(req, res) {
res.statusMessage = "Current password does not match";
res.status(400).end();
}
Then use curl to verify that it works:
$ curl -i -s http://localhost:3100/
HTTP/1.1 400 Current password does not match
X-Powered-By: Express
Date: Fri, 08 Apr 2016 19:04:35 GMT
Connection: keep-alive
Content-Length: 0
You can check this res.send(400, 'Current password does not match')
Look express 3.x docs for details
UPDATE for Expressjs 4.x
Use this way (look express 4.x docs):
res.status(400).send('Current password does not match');
// or
res.status(400);
res.send('Current password does not match');
You can use it like this
return res.status(400).json({'error':'User already exists.'});
One elegant way to handle custom errors like this in express is:
function errorHandler(err, req, res, next) {
var code = err.code;
var message = err.message;
res.writeHead(code, message, {'content-type' : 'text/plain'});
res.end(message);
}
(you can also use express' built-in express.errorHandler for this)
Then in your middleware, before your routes:
app.use(errorHandler);
Then where you want to create the error 'Current password does not match':
function checkPassword(req, res, next) {
// check password, fails:
var err = new Error('Current password does not match');
err.code = 400;
// forward control on to the next registered error handler:
return next(err);
}
At server side(Express middleware):
if(err) return res.status(500).end('User already exists.');
Handle at Client side
Angular:-
$http().....
.error(function(data, status) {
console.error('Repos error', status, data);//"Repos error" 500 "User already exists."
});
jQuery:-
$.ajax({
type: "post",
url: url,
success: function (data, text) {
},
error: function (request, status, error) {
alert(request.responseText);
}
});
When using Axios you can retrieve the custom response message with:
Axios.get(“your_url”)
.then(data => {
... do something
}.catch( err => {
console.log(err.response.data) // you want this
})
...after setting it in Express as:
res.status(400).send(“your custom message”)
My use-case is sending a custom JSON error message, since I'm using express to power my REST API. I think this is a fairly common scenario, so will focus on that in my answer.
Short Version:
Express Error Handling
Define error-handling middleware like other middleware, except with
four arguments instead of three, specifically with the signature (err,
req, res, next). ... You define error-handling middleware last, after
other app.use() and routes calls
app.use(function(err, req, res, next) {
if (err instanceof JSONError) {
res.status(err.status).json({
status: err.status,
message: err.message
});
} else {
next(err);
}
});
Raise errors from any point in the code by doing:
var JSONError = require('./JSONError');
var err = new JSONError(404, 'Uh oh! Can't find something');
next(err);
Long Version
The canonical way of throwing errors is:
var err = new Error("Uh oh! Can't find something");
err.status = 404;
next(err)
By default, Express handles this by neatly packaging it as a HTTP Response with code 404, and body consisting of the message string appended with a stack trace.
This doesn't work for me when I'm using Express as a REST server, for example. I'll want the error to be sent back as JSON, not as HTML. I'll also definitely not want my stack trace moving out to my client.
I can send JSON as a response using req.json(), eg. something like req.json({ status: 404, message: 'Uh oh! Can't find something'}). Optionally, I can set the status code using req.status(). Combining the two:
req.status(404).json({ status: 404, message: 'Uh oh! Can't find something'});
This works like a charm. That said, I find it quite unwieldy to type every time I have an error, and the code is no longer self-documenting like our next(err) was. It looks far too similar to how a normal (i.e, valid) response JSON is sent. Further, any errors thrown by the canonical approach still result in HTML output.
This is where Express' error handling middleware comes in. As part of my routes, I define:
app.use(function(err, req, res, next) {
console.log('Someone tried to throw an error response');
});
I also subclass Error into a custom JSONError class:
JSONError = function (status, message) {
Error.prototype.constructor.call(this, status + ': ' + message);
this.status = status;
this.message = message;
};
JSONError.prototype = Object.create(Error);
JSONError.prototype.constructor = JSONError;
Now, when I want to throw an Error in the code, I do:
var err = new JSONError(404, 'Uh oh! Can't find something');
next(err);
Going back to the custom error handling middleware, I modify it to:
app.use(function(err, req, res, next) {
if (err instanceof JSONError) {
res.status(err.status).json({
status: err.status,
message: err.message
});
} else {
next(err);
}
}
Subclassing Error into JSONError is important, as I suspect Express does an instanceof Error check on the first parameter passed to a next() to determine if a normal handler or an error handler must be invoked. I can remove the instanceof JSONError check and make minor modifications to ensure unexpected errors (such as a crash) also return a JSON response.
If your goal is just to reduce it to a single/simple line, you could rely on defaults a bit...
return res.end(res.writeHead(400, 'Current password does not match'));
Well in the case of Restify we should use sendRaw() method
Syntax is:
res.sendRaw(200, 'Operation was Successful', <some Header Data> or null)
I have a working node.js / express based server and am using jade for templating. Usually there is no problem but a couple of times every day I get an error message when requsting any page. The error is 'failed to locate view'. I don't know why i get this error since it worked fine just minutes before.
The question however is how I can force a crash on this event, for example:
res.render('index.jade', {info: 'msg'}, function(error, ok) {
if (error)
throw new Error('');
// Proceed with response
};
How would I do this? And how would I proceed with the response?
thank you.
You can add an error handling middleware.
app.use(function handleJadeErrors(err, req, res, next) {
// identify the errors you care about
if (err.message === 'failed to locate view') {
// do something sensible, such as logging and then crashing
// or returning something more useful to the client
} else {
// just pass it on to other error middleware
next(err);
}
});
Try this:
app.use(function (req, res, next) {
fs.exists(__dirname + '/views/' + req.url.substring(1) + '.jade', function (exists) {
if(!exists) {
console.log(err);
return next();
}
res.render(req.url.substring(1), { title: "No Controller", user: req.session.user });
}
});