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

Javascript Node.js-针对意外错误提供500页错误,javascript,node.js,http,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)

我试图从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');
}
尝试访问null的属性“c”会引发错误,因此永远不会到达“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事件,即: 进程。on('uncaughtException',doSomething)

但是我无法访问(req,res)参数,因此无法为正确的res实例调用res.end;访问它们的唯一方法是为每个传入请求将它们存储在更高的作用域对象中,然后在成功的请求解析中删除它们,然后在触发未捕获异常时将现有的[req,res]存储对标记为“潜在错误”,并在当前活动请求的计数与当前未解决错误的计数匹配时向这些请求提供500页(并重新测试每个抛出的未捕获预期和每个成功的res.end调用的计数)

这样做是可行的,但是。。。真是难看极了。这意味着请求对象必须泄漏到全局范围,这也意味着我的路由器模块现在依赖于uncaughtException全局事件,如果任何其他代码覆盖该事件,一切都会中断,或者如果我出于任何原因想要处理其他uncaughtException,我将陷入交叉依赖的地狱

这个问题的根本原因是意外错误可能发生在任何地方,但我想特别了解意外错误是否源于从传入http请求开始的堆栈跟踪(例如,不是从我在后台运行的某个时间间隔开始的,因为那时我会遇到一个意外错误,但显然不想向任何人提供500页的页面,只向管理员发送带有错误日志的电子邮件),除了需要知道错误是否源自http请求之外,我还需要访问节点服务器对象提供的请求+响应对象

没有更好的办法了吗

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

i、 例如,一个人正在为服务器编写基本代码,比如说“路由器模块”。其他人将来会向服务器添加新代码,处理路由到的分支

编写基本服务器代码的人必须以这样一种方式来编写:如果将来有任何代码编写错误并抛出错误,它将提供500页的服务。帮助他完成他的目标


回答格式为“确保所有未来添加代码的人永远不会出错,并且总是编写不会抛出未捕获错误的代码”将不被接受。

首先,在Nodejs中使用uncaughtException是不安全的。如果您觉得应用程序中没有其他选项,请确保在“uncaughtException”处理程序中退出该进程,并使用pm2或forever或其他一些模块重新启动该进程。下面的链接可以为您提供参考

说到错误处理过程,如前所述,您可能总是无法使用回调来处理错误。为了避免这些错误,我们可以使用nodejs中承诺的一个特殊优势

/* 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模型,并在应用程序中使用它们。

这并不能回答问题。问题是如何设计一台服务器,使其在运行过程中出错(假设20多名开发人员在一个代码库上工作),服务器的客户端将得到一个错误页面而不是超时。您的回答是“确保没有人犯错误,每个人都使用承诺,并在使用依赖项时将不基于承诺的代码转换为承诺”。这不是一个解决方案。我想问的是,如果有人确实生成了新代码,但抛出了一个未在其作用域中直接捕获的错误,如何处理这种情况。@Aqo:我认为您不熟悉使用承诺。承诺处理中的捕获块可以捕获未处理的异常,您可以安全地从承诺的捕获块返回。Yo你可以看看下面关于使用承诺的链接。我想你没有读过这个问题。这个问题首先说有一个错误。你不需要关心如何或为什么。有一个错误。我完全知道如何捕捉错误以及如何使用承诺,但这与这个问题无关。有一个http请求,请求c创建了一个错误,这是问题的基础。现在,我们如何向客户端提供响应(500页)?是否重新启动服务器、向文件写入日志、向管理员发送邮件等等,都超出了这个问题的范围。这个问题是关于在出现错误后提供500页的响应。