Node.js with Express - throw Error vs next(error)

2020-08-09 07:09发布

问题:

Can someone expound on the times when it's appropriate in a node.js Express app to throw an error like so:

throw new Error('my error');

or to pass this error on via the callback usually labelled 'next' like so:

next(error);

and could you please explain what each of them will do in the context of an Express app?

for example, here is an express function dealing with URL parameters:

app.param('lineup_id', function (req, res, next, lineup_id) {
        // typically we might sanity check that user_id is of the right format
        if (lineup_id == null) {
            console.log('null lineup_id');
            req.lineup = null;
            return next(new Error("lineup_id is null"));
        }

        var user_id = app.getMainUser()._id;
        var Lineup = app.mongooseModels.LineupModel.getNewLineup(app.system_db(), user_id);
        Lineup.findById(lineup_id, function (err, lineup) {
            if (err) {
                return next(err);
            }
            if (!lineup) {
                console.log('no lineup matched');
                return next(new Error("no lineup matched"));
            }
            req.lineup = lineup;
            return next();
        });
    });

In the line commented "//should I create my own error here?" I could used "throw new Error('xyz')", but what exactly would that do? Why is it usually better to pass the error to the callback 'next'?

Another question is - how do I get "throw new Error('xyz')" to show up in the console as well as the browser when I am in development?

回答1:

In general express follows the way of passing errors rather than throwing it, for any errors in the program you can pass the error object to 'next' , also an error handler need to be defined so that all the errors passed to next can be handled properly

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



回答2:

Errors that occur in synchronous code inside route handlers and middleware require no extra work. If synchronous code throws an error, then Express will catch and process it. For example:

app.get('/', function (req, res) {
  throw new Error('BROKEN') // Express will catch this on its own.
})


回答3:

Throwing an error inside a callback doesn't work:

app.get('/', function (req, res) {
  fs.mkdir('.', (err) => {
    if (err) throw err;
  });
});

But calling next works:

app.get('/', function (req, res, next) {
  fs.mkdir('.', (err) => {
    if (err) next(err);
  });
});


回答4:

For those who prefer throwing errors, here is a workaround decorator:

export function safeThrow(
    target: object,
    key: string | symbol,
    descriptor: TypedPropertyDescriptor<(req: Request, res: Response, next: NextFunction) => Promise<any>>) {
    const fun = descriptor.value;
    descriptor.value = async function () {
        try {
            await fun.apply(this, arguments);
        } catch (err) {
            arguments[2](err);
        }
    };
}

@safeThrow
private async get(req: Request, res: Response, next: NextFunction) {
  throw { status: 404, message: 'Not supported' }
}