簡體   English   中英

Node.js-在發生意外錯誤時提供錯誤500頁

[英]Node.js - Serving error 500 pages on unexpected errors

我試圖從我的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頁(以及向管理員發送電子郵件等)。

在每個塊中都使用“ try catch”是不可能的。 大多數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]存儲對標記為“潛在錯誤” uncaughtException觸發器觸發,並在當前活動請求的數量與當前未解決的錯誤的數量匹配時為這些請求提供500頁(並重新測試每個未拋出的期望和成功的res.end調用的計數)。

這樣做是可行的,但是……真是丑陋。 這意味着必須將請求對象泄漏到全局范圍,這也意味着我的路由器模塊現在對uncaughtException全局事件具有依賴性,並且如果任何其他代碼覆蓋了該事件,則一切都將中斷,或者如果我想無論出於何種原因處理其他未捕獲的異常,我都會遇到交叉依賴地獄。

造成此問題的根本原因是,任何地方都可能發生意外錯誤,但是我想專門捕獲意外錯誤是否源於從傳入的HTTP請求開始的堆棧跟蹤(例如,不是從我運行的某個時間間隔開始)在后台,因為這樣我會收到一個意外錯誤,但顯然不想為任何人提供500頁的服務,僅向管理員發送錯誤日志給電子郵件),並且還需要了解錯誤是否源自http請求,我需要訪問節點服務器對象提供的request + response對象。

有沒有更好的辦法?

[編輯]這個問題的主題是模塊中的角色分配。

也就是說,有一個人正在為服務器創建基礎代碼,可以說是“路由器模塊”。 將來,其他人將向服務器添加新代碼,以處理路由到的分支。

編寫基本服務器代碼的人必須以某種方式編寫它,如果將來任何不正確的代碼編寫並引發錯誤,它將服務500頁。 幫助他實現目標。

格式為“確保所有將來添加代碼的人都不會犯錯誤並且始終編寫不會拋出未捕獲的錯誤的代碼”的答案將不被接受。

首先,在Node.js中使用uncaughtException是不安全的。 如果您覺得應用程序中沒有其他選項,請確保在“ uncaughtException”處理程序中退出進程,然后使用pm2或永久或其他模塊重新啟動該進程。 下面的鏈接可以為您提供參考。

捕獲Node js應用程序的所有uncaughtException

如前所述,在錯誤處理過程中,您可能總是會錯過通過回調處理錯誤的機會。 為避免這種情況,我們可以在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模型,然后在應用程序中使用它們。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM