在Node.js和Express中处理404、500和异常

9
我有一个node.js + Express + express-handlebars应用程序。当用户访问不存在的页面时,我想将其重定向到404页面,并在出现内部服务器错误或异常时将其重定向到500(而不停止服务器)。在我的app.js中,我编写了中间件来执行这些任务。请注意,中间件应该放在最后。
app.get('*', function(req, res, next) {
    var err = new Error();
    err.status = 404;
    next();
});

//Handle 404
app.use(function(err, req, res, next){
    res.sendStatus(404);
    res.render('404');
    return;
});

//Handle 500
app.use(function(err, req, res, next){
    res.sendStatus(500);
    res.render('500');
});

//send the user to 500 page without shutting down the server
process.on('uncaughtException', function (err) {
  console.log('-------------------------- Caught exception: ' + err);
    app.use(function(err, req, res, next){
        res.render('500');
    });
});

然而,只有404的代码有效。因此,如果我尝试访问一个url,它将不会起作用。
localhost:8000/fakepage

它成功地将我重定向到404页面。505无效。对于异常处理,服务器确实保持运行状态,但在console.log之后不会将我重定向到500错误页面。
我对在线上有这么多解决方案感到困惑,人们似乎采用不同的技术来解决这个问题。
以下是我查看过的一些资源。

http://www.hacksparrow.com/express-js-custom-error-pages-404-and-500.html

在Express中处理404和500错误的正确方法

如何将404错误重定向到ExpressJS中的页面?

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

1个回答

16

uncaughtexception进程是应用程序进程的异常处理器,不是每个请求的错误处理器。注意它在回调中接收err参数而不传递res。它是一个全局应用程序异常处理器。若全局代码抛出异常,有它会很好。

一种选择是可以拥有所有正常路由(在你的示例中没有看到),然后添加一个非错误处理器最终的*路由用于404。这总是最后一个路由,表示它已经穿过所有其他路由未找到匹配... 因此未找到。这不是一个异常处理情况 - 你可以确定他们请求的路径没有匹配,因为它已经落空了。

如何将404错误重定向到ExpressJS中的页面?

然后,err路由可以返回500。

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

问题是你有两个错误路由,所以它总是先命中第一个,它硬编码返回404。

Express 4工具创建了这个模式:

var users = require('./routes/users');

// here's the normal routes.  Matches in order
app.use('/', routes);
app.use('/users', users);

// catch 404 and forward to error handler
// note this is after all good routes and is not an error handler
// to get a 404, it has to fall through to this route - no error involved
app.use(function(req, res, next) {
    var err = new Error('Not Found');
    err.status = 404;
    next(err);
});

// error handlers - these take err object.
// these are per request error handlers.  They have two so in dev
// you get a full stack trace.  In prod, first is never setup

// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
    app.use(function(err, req, res, next) {
        res.status(err.status || 500);
        res.render('error', {
            message: err.message,
            error: err
        });
    });
}

// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
    res.status(err.status || 500);
    res.render('error', {
        message: err.message,
        error: {}
    });
});

var profile = require('./routes/profile); app.use('/profie', profile); 这是我定义所有路由的方式。 - codeinprogress
没问题 - 这些路由应该在404路由和错误路由之前设置 - 基本上就是在/和/users路由设置之上。路由顺序至关重要。 - bryanmac
这就是上面示例的全部内容。它通过 require 用户加载用户函数,并通过传递用户来设置 /users 路由。然后在设置所有路由之后添加了 404 通配符路由,最后添加了错误 500 路由。 - bryanmac
谢谢您提供的示例。在旧代码中,我已经解决了404错误,但仍无法处理异常。例如,假设URL为/students/we232(其中we232是学生ID)。如果我将其更改为一些无意义或不存在的内容,我希望用户被重定向到500,而不是服务器关闭。我该如何实现这一点? - codeinprogress
在你所描述的情况下,获取学生路由将查找we232,得出结论它不存在,并返回404(在这种情况下应该做的)。每个请求未处理的处理程序(err,req,res,next)在这种情况下不会被调用,因为它已经“处理”了。500是用于未处理的服务器错误。当然,服务器不会崩溃,因为(1)它在该路由函数中被处理,(2)即使它以某种方式没有被处理,它也会返回500。应用程序级别的未捕获异常不是每个请求处理程序 - 它用于处理应用程序中的全局异常。 - bryanmac

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接