I'm working on a web app that works with node in server and react-redux in front-end.
The App is handling errors by redux in front-end and I want to use try-catch for the server because I want to keep my server working(sometimes because of one simple error server will be down).
But as try-catch is catching the error in the server after using try-catch in node (server) I'll not receive any message for that error in front-end( I have received a message related to error as I'm using redux)
My question is that: How can I handle my app to have error handling on both side? If I don't use try catch in the server, the server will be down. I want to have error-handling alongside in server and front-end.
For example, this is Update route in my app that I want to use try-catch, I have added this try-catch and now I can have the error in server console and in front-end by using a callback. But is it the correct way?
app.put('/updateadmin', function(req, res, cb){
var email = req.body.email,
// password = req.body.password,
name = req.body.name;
admin.updateAdmin(email, name, function(err, user){
if (err)
throw err;
try {
activity.insertActivity(user._id, 4, function(err){
if (err)
throw err;
});
} catch (ex) {
cb(ex);
console.log(ex);
}
});
});
Thanks for help
I found this way to handle errors in express site:
app.put('/updateadmin', function(req, res, next){
var email = req.body.email,
name = req.body.name;
admin.updateAdmin(email, name, function(err, user){
if (err)
return next(err);
activity.insertActivity(user._id, 4, function(err){
if (err)
return next(err);
});
});
});
and in the top level of your app like App.js, you should handle errors.
Related
My setup is as follows:
posting to /register will take the arguments and register a user via passport and mongoose. If this returns an UserExistsError the server sends this info to the client (via http error handling).
However the server also displays a 500 server error which should not occur.
This is because of the next() which as far as I understand routes the client to /register. /register itself does not exists as a page (only as the postadress as stated in the code)
So my question is: How to handle the response to not be an error or supress it? Can I use something else instead of next() to stop the redirect to /register? I just want the server to stop doing anything/going out of that function at that point.
Code:
app.post('/register', function(req, res, next) {
console.log('server registering user');
User.register(new User({username: req.body.username}), req.body.password, function(err) {
let tempstring = ""+err;
if(tempstring.indexOf("UserExistsError") !== -1){
return next(err); //get out of the function and into normal operation under '/'
}
});
});
This topic is bugging me and I might just missunderstand something trivial.
Even if /register is a post only route you still need to send a response. If you don't send a response of some kind, the request will hang and eventually timeout in the browser. I would suggest sending a json response like so.
app.post('/register', function(req, res, next) {
console.log('server registering user');
User.register(new User({username: req.body.username}), req.body.password, function(err) {
let tempstring = ""+err;
if(tempstring.indexOf("UserExistsError") !== -1){
return next(err); //get out of the function and into normal operation under '/'
}
res.json({message: 'message here'});
});
});
This will send a 200 OK reponse with some json in the body.
If you just want to pass the request down the line you need to call next without an err object like so.
app.post('/register', function(req, res, next) {
console.log('server registering user');
User.register(new User({username: req.body.username}), req.body.password, function(err) {
let tempstring = ""+err;
if(tempstring.indexOf("UserExistsError") !== -1){
return next(err); //get out of the function and into normal operation under '/'
}
//call next without an error
next();
});
});
I am not sure if this is what you are trying to achieve, but if there is no route that matches it will just go to an error 500.
I am new to Express and Node, and when testing a protected REST endpoint in my app using Advanced REST Client the data is returned from the endpoint to the Client as expected, however the console logs
"Error: Can't set headers after they are sent"
which stops the server. Searching here on SO, this seems to occur when sending more than one response but I don't see that in my code:
router.get('/books', userAuthenticated, function (req, res, next) {
Book.find({}, function(err, docs){
if(err) {
res.send(err)
} else {
res.send(docs);
// next();
// return;
}
})
});
Is this error expected when sending a request/response to/from the Client or am I missing something in handling the error on the server?
Express is a node.js server that features a concept called "middleware", where multiple layers of code get a chance to operate on a request.
In that case, not only do you need to check that your function is not sending back a response twice, but you have to check that other middleware are not sending back a response as well.
In your case, the code indicates that middleware called "userAuthenticated" is being invoked before this function. You should check if that middleware is already sending a response.
I don't think the problem was in the middleware. It looks like I was calling done() twice in passport deserialize. I commented out the first instance and the problem disappeared in all my routes. Although, I am not sure if I should comment out the first or second instance but I'll work on that next.
passport.deserializeUser(function(obj, done) {
console.log(obj);
Account.findById(obj, function(err, user) {
console.log(user);
//done(err, user);
});
return done(null, obj);
});
So I'm trying to set up a basic Todo list/CRUD application using the MEAN stack (Angular, MongoDB, Nodejs, Express) and I keep running into trouble when I switch around the routes and models in the directory and try to load up the application via node server on my command prompt. When I move anything the error below is what I get via a command prompt error. Just an FYI, I'm a total NOOB.
App listening on port 3000
GET /api/todos 404 2ms
GET /api/todos 500 7ms - 1.36kb
ReferenceError: Todo is not defined
at app.delete.Todo.remove._id (C:\Users\Basel\WebstormProjects\TEST\node-tod
o-tut1-starter\server.js:41:3)
at callbacks (C:\Users\Basel\WebstormProjects\TEST\node-todo-tut1-starter\no
de_modules\express\lib\router\index.js:164:37)
at param (C:\Users\Basel\WebstormProjects\TEST\node-todo-tut1-starter\node_m
odules\express\lib\router\index.js:138:11)
at pass (C:\Users\Basel\WebstormProjects\TEST\node-todo-tut1-starter\node_mo
dules\express\lib\router\index.js:145:5)
at Router._dispatch (C:\Users\Basel\WebstormProjects\TEST\node-todo-tut1-sta
rter\node_modules\express\lib\router\index.js:173:5)
at Object.router (C:\Users\Basel\WebstormProjects\TEST\node-todo-tut1-starte
r\node_modules\express\lib\router\index.js:33:10)
at next (C:\Users\Basel\WebstormProjects\TEST\node-todo-tut1-starter\node_mo
dules\express\node_modules\connect\lib\proto.js:193:15)
at Object.methodOverride [as handle] (C:\Users\Basel\WebstormProjects\TEST\n
ode-todo-tut1-starter\node_modules\express\node_modules\connect\lib\middleware\m
ethodOverride.js:48:5)
at next (C:\Users\Basel\WebstormProjects\TEST\node-todo-tut1-starter\node_mo
dules\express\node_modules\connect\lib\proto.js:193:15)
at multipart (C:\Users\Basel\WebstormProjects\TEST\node-todo-tut1-starter\no
de_modules\express\node_modules\connect\lib\middleware\multipart.js:86:27)
app.post('/api/todos', function(req, res) {
// create a todo, information comes from AJAX request from Angular
Todo.create({
text : req.body.text,
done : false
}, function(err, todo) {
if (err)
res.send(err);
// get and return all the todos after you create another
Todo.find(function(err, todos) {
if (err)
res.send(err)
res.json(todos);
});
});
});
// delete a todo
app.delete('/api/todos/:todo_id', function(req, res) {
Todo.remove({
_id : req.params.todo_id
}, function(err, todo) {
if (err)
res.send(err);
// get and return all the todos after you create another
Todo.find(function(err, todos) {
if (err)
res.send(err)
res.json(todos);
});
});
});
// application -------------------------------------------------------------
app.get('*', function(req, res) {
res.sendfile('./public/index.html'); // load the single view file (angular will handle the page changes on the front-end)
});
(Assuming you send correct _id from client) you have to reconstruct the _id as BSON object.
Do not know what db-driver you use, but in mongoskin it goes like that:
var mongo = require('mongoskin');
var BSON = mongo.BSONPure;
...
var proper_id = BSON.ObjectID(req.params.todo_id)
In mangoose try following:
var todo = Todo.find({_id : req.params.todo_id});
todo.remove(callback(err, todo)); // callback is optional
I am using node-mongodb-native driver. I tried
collection.findOne({email: 'a#mail.com'}, function(err, result) {
if (!result) throw new Error('Record not found!');
});
But the error is caught by mongodb driver and the express server is terminated.
What's the correct way for this case?
=== Edit===
I have the code below in app.js
app.configure('development', function() {
app.use(express.errorHandler({dumpExceptions: true, showStack: true}));
});
app.configure('production', function() {
app.use(express.errorHandler());
});
Related code in node_modules/mongodb/lib/mongodb/connection/server.js
connectionPool.on("message", function(message) {
try {
......
} catch (err) {
// Throw error in next tick
process.nextTick(function() {
throw err; // <-- here throws an uncaught error
})
}
});
The correct use is not to throw an error, but to pass it to next function. First you define the error handler:
app.error(function (err, req, res, next) {
res.render('error_page.jade');
})
(What's this talk about error being depracated? I don't know anything about that. But even if then you can just use use. The mechanism is still the same.).
Now in your route you pass the error to the handler like this:
function handler(req, res, next) {
collection.findOne({email: 'a#mail.com'}, function(err, result) {
if (!result) {
var myerr = new Error('Record not found!');
return next(myerr); // <---- pass it, not throw it
}
res.render('results.jade', { results: result });
});
};
Make sure that no other code (related to the response) is fired after next(myerr); (that's why I used return there).
Side note: Errors thrown in asynchronous operations are not handled well by Express (well, actually they somewhat are, but that's not what you need). This may crash your app. The only way to capture them is by using
process.on('uncaughtException', function(err) {
// handle it here, log or something
});
but this is a global exception handler, i.e. you cannot use it to send the response to the user.
I'm guessing that the error is not caught. Are you using an Express error handler? Something like:
app.error(function (err, req, res, next) {
res.render('error-page', {
status: 404
});
More on error handling in Express: http://expressjs.com/guide.html#error-handling
In terms of checking for errors off mongodb, use '!error' for success as opposed to '!result' for errors.
collection.findOne({email: 'a#mail.com'}, function(err, result) {
if (!error) {
// do good stuff;
} else {
throw new Error('Record not found!');
}
});
As for the custom 404, I've yet to do that in node and express, but I would imagine it would involve "app.router".
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 });
}
});