Node.js - 针对意外错误提供500页错误

时间:2018-06-02 16:40:28

标签: javascript node.js http

我试图从我的Node.js服务器向500页(一些通用的HTML,表示" 500 - 内部服务器错误")提供由于开发人员错误而无法解决的请求,但是无法找到一种优雅的方式来做到这一点。

假设我们有以下index.js,开发人员无辜地犯了一个错误:

const http = require('http');
const port = 12345;

http.createServer(onHttpRequest).listen(port);

function onHttpRequest(req, res) {
    var a = null;
    var b = a.c; // this is the mistake

    res.end('status: 200');
}

试图访问财产" c" null抛出一个错误,所以" res.end"永远不会到达。因此,请求客户端最终会超时。理想情况下,我的服务器上有代码可以捕获这样的错误,并向请求客户端返回500页(以及向管理员发送电子邮件等)。

使用"尝试捕获"在每一个街区都是不可能的。大多数Node.js代码都是异步的,很多代码都依赖于外部库,并且有可疑的错误处理。即使我在任何地方使用try-catch,也有可能在外部库中发生错误,该库在其内部没有try-catch块,在异步发生的函数中,因此我的服务器将崩溃,客户端永远不会得到响应。

我能提供的最短的例子:

/* my server's index.js */

const http = require('http');
const poorlyTestedNpmModule = require('some-npm-module');
const port = 12345;

http.createServer(onHttpRequest).listen(port);

function onHttpRequest(req, res) {
    try {
        poorlyTestedNpmModule(null, onResult);
    }
    catch(err) {
        res.end('status: 500');
    }

    function onResult(err, expectedResult) {
        if(err) {
            res.end('status: 400');
        }
        else {
            res.end('status: 200');
        }
    }
}

/* some-npm-module.js */

module.exports = function poorlyTestedNpmModule(options, callback) {
    setTimeout(afterSomething, 100);

    function afterSomething() {
        var someValue = options.key; // here's the problem
        callback(null, someValue);
    }
}

这里,由于函数调用导致异步抛出错误的代码,服务器崩溃。此代码不是我控制或希望修改的代码;我希望我的服务器能够自己处理所有这些错误。

现在,我可以使用全局的uncaughtException事件,即:     process.on(' uncaughtException',doSomething);

但是我无法访问(req,res)参数,因此无法为正确的res实例调用res.end;访问它们的唯一方法是将它们存储在每个传入请求的更高范围的对象中,然后在成功的请求解析时修剪它们,然后将现有的[req,res]存储对标记为"可能出错并且#34;每当一个uncaughtException触发时,只要当前活动请求的数量与当前未解决的错误数相匹配(并重新测试每次抛出未捕获的预期和每次成功的res.end调用的计数),就会向这些请求提供500个页面。 / p>

这样做有用,但是......它很难看。这意味着请求对象必须泄漏到全局范围,这也意味着我的路由器模块现在依赖于uncaughtException全局事件,如果任何其他代码覆盖该事件,一切都中断,或者如果我想要无论出于何种原因处理其他未被捕获的异常,我都会陷入交叉依赖地狱。

此问题的根本原因是任何地方都可能发生意外错误,但我想特别捕获是否是从传入的http请求开始的堆栈跟踪中发生的意外错误(例如,不是来自某个时间间隔我在后台运行,因为那时我遇到了意外错误,但显然不想向任何人提供500页,只向管理员发送错误日志,并且需要知道是否有错误源自http请求,我需要访问节点服务器对象提供的请求+响应对象。

有没有更好的方法?

[编辑]这个问题的主题是模块中的角色分配。

即,一个人正在为服务器制作基本代码,让我们说一个"路由器模块"。其他人将来会向服务器添加新代码,处理路由到的分支。

编写基本服务器代码的人必须以一种方式编写它,如果任何未来的代码写得不正确并抛出错误,它将提供500页。帮助他实现目标。

格式的答案"确保所有未来添加代码的人永远不会犯错误,并且总是编写不会丢失未捕获错误的代码"将不被接受。

1 个答案:

答案 0 :(得分:0)

首先,在Nodejs中使用uncaughtException并不安全。如果您认为应用程序中没有其他选项,请确保在“未捕获的异常”处理程序中退出该过程。并使用pm2或永久或其他模块重新启动进程。以下链接可为您提供参考。

Catch all uncaughtException for Node js app

如上所述,在进行错误处理的过程中,您可能总是错过使用回调处理错误。为了避免这些,我们可以在nodejs中使用promises的特殊优势。

/* my server's index.js */

const http = require('http');
const poorlyTestedNpmModule = require('some-npm-module');
const port = 12345;

http.createServer(onHttpRequest).listen(port);

function onHttpRequest(req, res) { 

   try {
            poorlyTestedNpmModule(null)
            .then(result => {
                res.end('status: 200');
            })
            .catch(err =>{
              console.log('err is', err);
              res.end('status: 400');
            })
       }
    catch(err) {
                res.end('status: 500');
    }

}


/* some-npm-module.js */

module.exports = function poorlyTestedNpmModule(options, callback) {
    setTimeout(afterSomething, 100);

   afterSomthing = new Promise((resolve, reject)=> {
       var someValue = options.key; // here's the problem
       resolve(someValue);

   })
}

如果您看到某些npm节点模块不存在promise,请尝试编写包装器以将回调转换为promise模型并在应用程序中使用它们。